blob: bd4778d79c9ab536bb9770c777da76246a7a852a [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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Michael Sevakis5efee7c2006-11-06 18:18:05 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdlib.h>
22#include "system.h"
23#include "kernel.h"
24#include "logf.h"
25#include "audio.h"
Michael Sevakisc2d21062007-03-11 06:21:43 +000026#include "sound.h"
Michael Sevakis8f659ae2007-05-20 20:26:36 +000027#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +000028#include "spdif.h"
29#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +000030
Michael Sevakis8867d002007-03-05 08:14:27 +000031#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
32 (IIS_PLAY & (7 << 8)) | \
33 (4 << 2) ) /* 64 bit clocks / word clock */
34#define IIS_FIFO_RESET (1 << 11)
35#define PDIR2_FIFO_RESET (1 << 9)
Michael Sevakis5efee7c2006-11-06 18:18:05 +000036
Jens Arnold3005cf52008-03-15 21:55:14 +000037#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
Michael Sevakis8867d002007-03-05 08:14:27 +000038#define SET_IIS_PLAY(x) IIS1CONFIG = (x)
39#define IIS_PLAY IIS1CONFIG
40#else
41#define SET_IIS_PLAY(x) IIS2CONFIG = (x)
42#define IIS_PLAY IIS2CONFIG
43#endif
44
Michael Sevakis6077e5b2007-10-06 22:27:27 +000045struct dma_lock
46{
47 int locked;
48 unsigned long state;
49};
50
Michael Sevakis633f3882007-03-07 06:23:02 +000051static bool is_playback_monitoring(void)
52{
53 return (IIS_PLAY & (7 << 8)) == (3 << 8);
54}
55
56static void iis_play_reset_if_playback(bool if_playback)
57{
58 bool is_playback = is_playback_monitoring();
59
60 if (is_playback != if_playback)
61 return;
62
63 or_l(IIS_FIFO_RESET, &IIS_PLAY);
64}
65
Michael Sevakis5efee7c2006-11-06 18:18:05 +000066#define PLLCR_SET_AUDIO_BITS_DEFPARM \
67 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
Michael Sevakis5efee7c2006-11-06 18:18:05 +000068
69/** Sample rates **/
70#define FPARM_CLOCKSEL 0
71#define FPARM_CLSEL 1
72#define FPARM_FSEL 2
73#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
74static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
75{
76 [HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
77 [HW_FREQ_44] = { 0x06, 0x01, 0x02 },
78 [HW_FREQ_22] = { 0x04, 0x02, 0x01 },
79 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
80};
81#endif
82
Jens Arnold8a6291d2008-03-14 08:54:54 +000083#if (CONFIG_CPU == MCF5250 || CONFIG_CPU == MCF5249) && defined(HAVE_TLV320)
Michael Sevakis5efee7c2006-11-06 18:18:05 +000084static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
85{
86 [HW_FREQ_88] = { 0x0c, 0x01, 0x02 },
87 [HW_FREQ_44] = { 0x06, 0x01, 0x01 },
88 [HW_FREQ_22] = { 0x04, 0x01, 0x00 },
89 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
90};
91#endif
92
Michael Sevakis6077e5b2007-10-06 22:27:27 +000093static unsigned long pcm_freq = 0; /* 44.1 is default */
Michael Sevakis5efee7c2006-11-06 18:18:05 +000094static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
95
96/* set frequency used by the audio hardware */
97void pcm_set_frequency(unsigned int frequency)
98{
99 int index;
100
101 switch(frequency)
102 {
103 case SAMPR_11:
104 index = HW_FREQ_11;
105 break;
106 case SAMPR_22:
107 index = HW_FREQ_22;
108 break;
109 default:
110 case SAMPR_44:
111 index = HW_FREQ_44;
112 break;
113 case SAMPR_88:
114 index = HW_FREQ_88;
115 break;
116 }
117
118 /* remember table entry and rate */
119 freq_ent = pcm_freq_parms[index];
120 pcm_freq = hw_freq_sampr[index];
121} /* pcm_set_frequency */
122
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000123/* apply audio settings */
Bertrik Sikken19425902008-05-03 21:33:00 +0000124static bool _pcm_apply_settings(bool clear_reset)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000125{
Michael Sevakis633f3882007-03-07 06:23:02 +0000126 bool did_reset = false;
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000127 unsigned long iis_play_defparm = IIS_PLAY_DEFPARM;
Michael Sevakis8867d002007-03-05 08:14:27 +0000128
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000129 if (pcm_freq != pcm_curr_sampr)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000130 {
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000131 pcm_curr_sampr = pcm_freq;
Michael Sevakis8867d002007-03-05 08:14:27 +0000132 /* Reprogramming bits 15-12 requires FIFO to be in a reset
133 condition - Users Manual 17-8, Note 11 */
134 or_l(IIS_FIFO_RESET, &IIS_PLAY);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000135 /* Important for TLV320 - this must happen in the correct order
136 or starting recording will sound absolutely awful once in
137 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
138 */
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000139 SET_IIS_PLAY(iis_play_defparm | IIS_FIFO_RESET);
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000140 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000141 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
Michael Sevakis633f3882007-03-07 06:23:02 +0000142 did_reset = true;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000143 }
144
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000145 /* If a reset was done because of a sample rate change, IIS_PLAY will have
146 been set already, so only needs to be set again if the reset flag must
147 be cleared. If the frequency didn't change, it was never altered and
148 the reset flag can just be removed or no action taken. */
149 if (clear_reset)
150 SET_IIS_PLAY(iis_play_defparm & ~IIS_FIFO_RESET);
Michael Sevakis8867d002007-03-05 08:14:27 +0000151#if 0
152 logf("IISPLAY: %08X", IIS_PLAY);
153#endif
Michael Sevakis633f3882007-03-07 06:23:02 +0000154
155 return did_reset;
Michael Sevakis8867d002007-03-05 08:14:27 +0000156} /* _pcm_apply_settings */
157
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000158/* apply audio setting with all DMA interrupts disabled */
Bertrik Sikken19425902008-05-03 21:33:00 +0000159static void _pcm_apply_settings_irq_lock(bool clear_reset)
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000160{
161 int level = set_irq_level(DMA_IRQ_LEVEL);
162 _pcm_apply_settings(clear_reset);
Michael Sevakisaf395f42008-03-26 01:50:41 +0000163 restore_irq(level);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000164}
165
Michael Sevakis633f3882007-03-07 06:23:02 +0000166/* This clears the reset bit to enable monitoring immediately if monitoring
167 recording sources or always if playback is in progress - we might be
168 switching samplerates on the fly */
Michael Sevakis8867d002007-03-05 08:14:27 +0000169void pcm_apply_settings(void)
170{
Michael Sevakis633f3882007-03-07 06:23:02 +0000171 int level = set_irq_level(DMA_IRQ_LEVEL);
172 bool pbm = is_playback_monitoring();
173 bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
174
175 /* Clear reset if not playback monitoring or peripheral request is
176 active and playback monitoring */
177 if (_pcm_apply_settings(!pbm || kick) && kick)
178 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
179
Michael Sevakisaf395f42008-03-26 01:50:41 +0000180 restore_irq(level);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000181} /* pcm_apply_settings */
182
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000183void pcm_play_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000184{
Michael Sevakis8867d002007-03-05 08:14:27 +0000185 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
186 | (1 << 7) /* PDIR2 fifo auto sync */
187#ifdef HAVE_SPDIF_OUT
188 | (1 << 10) /* EBU TX auto sync */
189#endif
190 ;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000191 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
Michael Sevakis8867d002007-03-05 08:14:27 +0000192 and_l(0xffffff00, &DMAROUTE);
193 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000194 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
195
Michael Sevakis8867d002007-03-05 08:14:27 +0000196 /* Call pcm_play_dma_stop to initialize everything. */
197 pcm_play_dma_stop();
Michael Sevakis5d637762007-03-11 05:04:48 +0000198
Michael Sevakisabf41e32007-03-13 15:05:46 +0000199 /* Setup Coldfire I2S before initializing hardware or changing
200 other settings. */
201 or_l(IIS_FIFO_RESET, &IIS_PLAY);
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000202 SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000203 pcm_set_frequency(HW_FREQ_DEFAULT);
204 audio_set_output_source(AUDIO_SRC_PLAYBACK);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000205
Michael Sevakis5d637762007-03-11 05:04:48 +0000206 /* Initialize default register values. */
207 audiohw_init();
208
Michael Sevakis2d48d0f2007-06-08 23:42:04 +0000209 audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000210
Michael Sevakisabf41e32007-03-13 15:05:46 +0000211 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
212 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000213
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000214#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +0000215 spdif_init();
216#endif
Michael Sevakis633f3882007-03-07 06:23:02 +0000217 /* Enable interrupt at level 6, priority 0 */
218 ICR6 = (6 << 2);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000219} /* pcm_play_dma_init */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000220
Michael Sevakisc2d21062007-03-11 06:21:43 +0000221void pcm_postinit(void)
222{
223 audiohw_postinit();
224}
225
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000226/** DMA **/
227
228/****************************************************************************
229 ** Playback DMA transfer
230 **/
231/* For the locks, DMA interrupt must be disabled when manipulating the lock
232 if the handler ever calls these - right now things are arranged so it
233 doesn't */
234static struct dma_lock dma_play_lock =
235{
236 .locked = 0,
237 .state = (0 << 14) /* bit 14 is DMA0 */
238};
239
240void pcm_play_lock(void)
241{
242 if (++dma_play_lock.locked == 1)
243 or_l((1 << 14), &IMR);
244}
245
246void pcm_play_unlock(void)
247{
248 if (--dma_play_lock.locked == 0)
249 and_l(~dma_play_lock.state, &IMR);
250}
251
252/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
253void pcm_play_dma_start(const void *addr, size_t size)
254{
255 logf("pcm_play_dma_start");
256
257 /* stop any DMA in progress */
258 DSR0 = 1;
259 DCR0 = 0;
260
261 /* Set up DMA transfer */
262 SAR0 = (unsigned long)addr; /* Source address */
263 DAR0 = (unsigned long)&PDOR3; /* Destination address */
264 BCR0 = (unsigned long)size; /* Bytes to transfer */
265
266 /* Enable the FIFO and force one write to it */
267 _pcm_apply_settings_irq_lock(is_playback_monitoring());
268
269 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
270 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
271
272 dma_play_lock.state = (1 << 14);
273} /* pcm_play_dma_start */
274
275/* Stops the DMA transfer and interrupt */
276void pcm_play_dma_stop(void)
277{
278 DSR0 = 1;
279 DCR0 = 0;
280 BCR0 = 0;
281
282 /* Place TX FIFO in reset condition if playback monitoring is on.
283 Recording monitoring something else should not be stopped. */
284 iis_play_reset_if_playback(true);
285
286 dma_play_lock.state = (0 << 14);
287} /* pcm_play_dma_stop */
288
289void pcm_play_dma_pause(bool pause)
290{
291 if (pause)
292 {
293 /* pause playback on current buffer */
294 and_l(~DMA_EEXT, &DCR0);
295 iis_play_reset_if_playback(true);
296 dma_play_lock.state = (0 << 14);
297 }
298 else
299 {
300 /* restart playback on current buffer */
301 /* Enable the FIFO and force one write to it */
302 _pcm_apply_settings_irq_lock(is_playback_monitoring());
303 or_l(DMA_EEXT | DMA_START, &DCR0);
304 dma_play_lock.state = (1 << 14);
305 }
306} /* pcm_play_dma_pause */
307
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000308size_t pcm_get_bytes_waiting(void)
309{
310 return BCR0 & 0xffffff;
311} /* pcm_get_bytes_waiting */
312
313/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
314 from the caller's buffer */
315void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
316void DMA0(void)
317{
318 int res = DSR0;
319
Michael Sevakis8867d002007-03-05 08:14:27 +0000320 DSR0 = 1; /* Clear interrupt */
321 and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000322 /* Stop on error */
323 if ((res & 0x70) == 0)
324 {
325 pcm_more_callback_type get_more = pcm_callback_for_more;
326 unsigned char *next_start;
327 size_t next_size = 0;
328
329 if (get_more)
330 get_more(&next_start, &next_size);
331
332 if (next_size > 0)
333 {
334 SAR0 = (unsigned long)next_start; /* Source address */
335 BCR0 = next_size; /* Bytes to transfer */
Michael Sevakis8867d002007-03-05 08:14:27 +0000336 or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000337 return;
338 }
339 else
340 {
341 /* Finished playing */
342#if 0
343 /* int. logfs can trash the display */
344 logf("DMA0 No Data:0x%04x", res);
345#endif
346 }
347 }
348 else
349 {
Michael Sevakis8867d002007-03-05 08:14:27 +0000350 logf("DMA0 err: %02x", res);
351#if 0
352 logf(" SAR0: %08x", SAR0);
353 logf(" DAR0: %08x", DAR0);
354 logf(" BCR0: %08x", BCR0);
355 logf(" DCR0: %08x", DCR0);
356#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000357 }
358
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000359 /* Stop interrupt and futher transfers */
360 pcm_play_dma_stop();
361 /* Inform PCM that we're done */
362 pcm_play_dma_stopped_callback();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000363} /* DMA0 */
364
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000365const void * pcm_play_dma_get_peak_buffer(int *count)
366{
367 unsigned long addr = SAR0;
368 int cnt = BCR0;
369 *count = (cnt & 0xffffff) >> 2;
370 return (void *)((addr + 2) & ~3);
371} /* pcm_play_dma_get_peak_buffer */
372
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000373/****************************************************************************
374 ** Recording DMA transfer
375 **/
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000376static struct dma_lock dma_rec_lock =
377{
378 .locked = 0,
379 .state = (0 << 15) /* bit 15 is DMA1 */
380};
381
382/* For the locks, DMA interrupt must be disabled when manipulating the lock
383 if the handler ever calls these - right now things are arranged so it
384 doesn't */
385void pcm_rec_lock(void)
386{
387 if (++dma_rec_lock.locked == 1)
388 or_l((1 << 15), &IMR);
389}
390
391void pcm_rec_unlock(void)
392{
393 if (--dma_rec_lock.locked == 0)
394 and_l(~dma_rec_lock.state, &IMR);
395}
396
Michael Sevakis51189b42006-12-06 08:34:55 +0000397void pcm_rec_dma_start(void *addr, size_t size)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000398{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000399 /* stop any DMA in progress */
400 and_l(~DMA_EEXT, &DCR1);
401 DSR1 = 1;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000402
Michael Sevakis8867d002007-03-05 08:14:27 +0000403 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000404 /* Clear TX FIFO reset bit if the source is not set to monitor playback
Michael Sevakis8867d002007-03-05 08:14:27 +0000405 otherwise maintain independence between playback and recording. */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000406 _pcm_apply_settings_irq_lock(!is_playback_monitoring());
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000407
408 /* Start the DMA transfer.. */
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000409#ifdef HAVE_SPDIF_REC
Michael Sevakis521d6a52007-04-18 02:07:56 +0000410 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
411 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000412#endif
413
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000414 SAR1 = (unsigned long)&PDIR2; /* Source address */
415 pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
416 DAR1 = (unsigned long)addr; /* Destination address */
417 BCR1 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakis51189b42006-12-06 08:34:55 +0000418
Michael Sevakisf51df0d2006-12-12 04:25:52 +0000419 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000420 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
Michael Sevakis633f3882007-03-07 06:23:02 +0000421
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000422 dma_rec_lock.state = (1 << 15);
423} /* pcm_rec_dma_start */
Michael Sevakis633f3882007-03-07 06:23:02 +0000424
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000425void pcm_rec_dma_stop(void)
426{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000427 DSR1 = 1; /* Clear interrupt */
428 DCR1 = 0;
429 BCR1 = 0;
430 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000431
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000432 iis_play_reset_if_playback(false);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000433
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000434 dma_rec_lock.state = (0 << 15);
Michael Sevakis633f3882007-03-07 06:23:02 +0000435} /* pcm_rec_dma_stop */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000436
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000437void pcm_rec_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000438{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000439 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
440 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
Michael Sevakis8867d002007-03-05 08:14:27 +0000441 and_l(0xffff00ff, &DMAROUTE);
442 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000443
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000444 pcm_rec_dma_stop();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000445
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000446 /* Enable interrupt at level 6, priority 1 */
447 ICR7 = (6 << 2) | (1 << 0);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000448} /* pcm_init_recording */
449
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000450void pcm_rec_dma_close(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000451{
Michael Sevakis8867d002007-03-05 08:14:27 +0000452 and_l(0xffff00ff, &DMAROUTE);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000453 ICR7 = 0x00; /* Disable interrupt */
454 dma_rec_lock.state = (0 << 15);
455} /* pcm_rec_dma_close */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000456
457/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
458 into the caller's buffer */
459void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
460void DMA1(void)
461{
462 int res = DSR1;
Michael Sevakis51189b42006-12-06 08:34:55 +0000463 int status = 0;
464 pcm_more_callback_type2 more_ready;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000465
Michael Sevakis8867d002007-03-05 08:14:27 +0000466 DSR1 = 1; /* Clear interrupt */
467 and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000468
469 if (res & 0x70)
470 {
Michael Sevakis51189b42006-12-06 08:34:55 +0000471 status = DMA_REC_ERROR_DMA;
Michael Sevakis8867d002007-03-05 08:14:27 +0000472 logf("DMA1 err: %02x", res);
473#if 0
474 logf(" SAR1: %08x", SAR1);
475 logf(" DAR1: %08x", DAR1);
476 logf(" BCR1: %08x", BCR1);
477 logf(" DCR1: %08x", DCR1);
478#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000479 }
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000480#ifdef HAVE_SPDIF_REC
Michael Sevakisab1861a2006-11-23 19:21:15 +0000481 else if (DATAINCONTROL == 0xc038 &&
Michael Sevakis521d6a52007-04-18 02:07:56 +0000482 (INTERRUPTSTAT & ((1 << 24) | (1 << 23) | (1 << 22))))
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000483 {
Michael Sevakis521d6a52007-04-18 02:07:56 +0000484 /* reason: valnogood, symbolerr, parityerr */
485 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
486 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
Michael Sevakis51189b42006-12-06 08:34:55 +0000487 status = DMA_REC_ERROR_SPDIF;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000488 logf("spdif err");
489 }
490#endif
491
492 more_ready = pcm_callback_more_ready;
493
Michael Sevakis51189b42006-12-06 08:34:55 +0000494 if (more_ready != NULL && more_ready(status) >= 0)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000495 return;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000496
Michael Sevakis51189b42006-12-06 08:34:55 +0000497#if 0
498 /* int. logfs can trash the display */
499 logf("DMA1 done:%04x %d", res, status);
500#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000501 /* Finished recording */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000502 pcm_rec_dma_stop();
503 /* Inform PCM that we're done */
504 pcm_rec_dma_stopped_callback();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000505} /* DMA1 */
506
Michael Sevakis633f3882007-03-07 06:23:02 +0000507/* Continue transferring data in - call from interrupt callback */
Michael Sevakis51189b42006-12-06 08:34:55 +0000508void pcm_record_more(void *start, size_t size)
509{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000510 pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
511 DAR1 = (unsigned long)start; /* Destination address */
512 BCR1 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakis8867d002007-03-05 08:14:27 +0000513 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000514} /* pcm_record_more */
Michael Sevakis51189b42006-12-06 08:34:55 +0000515
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000516const void * pcm_rec_dma_get_peak_buffer(int *count)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000517{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000518 unsigned long addr = (unsigned long)pcm_rec_peak_addr;
519 unsigned long end = DAR1;
520 addr >>= 2;
521 *count = (end >> 2) - addr;
522 return (void *)(addr << 2);
523} /* pcm_rec_dma_get_peak_buffer */