diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/sh/archos/audio-archos.c | 563 | ||||
-rw-r--r-- | firmware/target/sh/archos/mascodec-archos.c | 485 |
2 files changed, 1048 insertions, 0 deletions
diff --git a/firmware/target/sh/archos/audio-archos.c b/firmware/target/sh/archos/audio-archos.c new file mode 100644 index 0000000000..e2d8b6f157 --- /dev/null +++ b/firmware/target/sh/archos/audio-archos.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Code that has been in mpeg.c before, now creating an encapsulated play | ||
11 | * data module, to be used by other sources than file playback as well. | ||
12 | * | ||
13 | * Copyright (C) 2004 by Linus Nielsen Feltzing | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | #include <stdbool.h> | ||
25 | #include "config.h" | ||
26 | #include "debug.h" | ||
27 | #include "panic.h" | ||
28 | #include <kernel.h> | ||
29 | #include "mp3_playback.h" | ||
30 | #include "sound.h" | ||
31 | #include "i2c.h" | ||
32 | #include "system.h" | ||
33 | #include "audiohw.h" | ||
34 | |||
35 | /* hacking into mpeg.c, recording is still there */ | ||
36 | #if CONFIG_CODEC == MAS3587F | ||
37 | enum | ||
38 | { | ||
39 | MPEG_DECODER, | ||
40 | MPEG_ENCODER | ||
41 | } mpeg_mode; | ||
42 | #endif /* #ifdef MAS3587F */ | ||
43 | |||
44 | #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR) | ||
45 | extern unsigned long shadow_io_control_main; | ||
46 | extern unsigned shadow_codec_reg0; | ||
47 | #endif | ||
48 | |||
49 | /**** globals ****/ | ||
50 | |||
51 | /* own version, independent of mpeg.c */ | ||
52 | static bool paused; /* playback is paused */ | ||
53 | static bool playing; /* We are playing an MP3 stream */ | ||
54 | |||
55 | /* for measuring the play time */ | ||
56 | static long playstart_tick; | ||
57 | static long cumulative_ticks; | ||
58 | |||
59 | /* the registered callback function to ask for more mp3 data */ | ||
60 | static void (*callback_for_more)(unsigned char**, size_t*); | ||
61 | |||
62 | /* list of tracks in memory */ | ||
63 | #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */ | ||
64 | #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1) | ||
65 | |||
66 | bool audio_is_initialized = false; | ||
67 | |||
68 | /* FIX: this code pretty much assumes a MAS */ | ||
69 | |||
70 | /* dirty calls to mpeg.c */ | ||
71 | extern void playback_tick(void); | ||
72 | extern void rec_tick(void); | ||
73 | |||
74 | unsigned long mas_version_code; | ||
75 | |||
76 | #if CONFIG_CODEC == MAS3507D | ||
77 | static void mas_poll_start(void) | ||
78 | { | ||
79 | unsigned int count; | ||
80 | |||
81 | count = 9 * FREQ / 10000 / 8; /* 0.9 ms */ | ||
82 | |||
83 | /* We are using timer 1 */ | ||
84 | |||
85 | TSTR &= ~0x02; /* Stop the timer */ | ||
86 | TSNC &= ~0x02; /* No synchronization */ | ||
87 | TMDR &= ~0x02; /* Operate normally */ | ||
88 | |||
89 | TCNT1 = 0; /* Start counting at 0 */ | ||
90 | GRA1 = count; | ||
91 | TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ | ||
92 | |||
93 | /* Enable interrupt on level 5 */ | ||
94 | IPRC = (IPRC & ~0x000f) | 0x0005; | ||
95 | |||
96 | TSR1 &= ~0x02; | ||
97 | TIER1 = 0xf9; /* Enable GRA match interrupt */ | ||
98 | |||
99 | TSTR |= 0x02; /* Start timer 1 */ | ||
100 | } | ||
101 | #elif CONFIG_CODEC != SWCODEC | ||
102 | static void postpone_dma_tick(void) | ||
103 | { | ||
104 | unsigned int count; | ||
105 | |||
106 | count = 8 * FREQ / 10000 / 8; /* 0.8 ms */ | ||
107 | |||
108 | /* We are using timer 1 */ | ||
109 | |||
110 | TSTR &= ~0x02; /* Stop the timer */ | ||
111 | TSNC &= ~0x02; /* No synchronization */ | ||
112 | TMDR &= ~0x02; /* Operate normally */ | ||
113 | |||
114 | TCNT1 = 0; /* Start counting at 0 */ | ||
115 | GRA1 = count; | ||
116 | TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ | ||
117 | |||
118 | /* Enable interrupt on level 5 */ | ||
119 | IPRC = (IPRC & ~0x000f) | 0x0005; | ||
120 | |||
121 | TSR1 &= ~0x02; | ||
122 | TIER1 = 0xf9; /* Enable GRA match interrupt */ | ||
123 | |||
124 | TSTR |= 0x02; /* Start timer 1 */ | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
129 | void demand_irq_enable(bool on) | ||
130 | { | ||
131 | int oldlevel = disable_irq_save(); | ||
132 | |||
133 | if(on) | ||
134 | { | ||
135 | IPRA = (IPRA & 0xfff0) | 0x000b; | ||
136 | ICR &= ~0x0010; /* IRQ3 level sensitive */ | ||
137 | } | ||
138 | else | ||
139 | IPRA &= 0xfff0; | ||
140 | |||
141 | restore_irq(oldlevel); | ||
142 | } | ||
143 | #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
144 | |||
145 | |||
146 | static void play_tick(void) | ||
147 | { | ||
148 | if(playing && !paused) | ||
149 | { | ||
150 | /* Start DMA if it is disabled and the DEMAND pin is high */ | ||
151 | if(!(SCR0 & 0x80) && (PBDR & 0x4000)) | ||
152 | { | ||
153 | SCR0 |= 0x80; | ||
154 | } | ||
155 | |||
156 | playback_tick(); /* dirty call to mpeg.c */ | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void DEI3(void) __attribute__((interrupt_handler)); | ||
161 | void DEI3(void) | ||
162 | { | ||
163 | unsigned char* start; | ||
164 | size_t size = 0; | ||
165 | |||
166 | if (callback_for_more != NULL) | ||
167 | { | ||
168 | callback_for_more(&start, &size); | ||
169 | } | ||
170 | |||
171 | if (size > 0) | ||
172 | { | ||
173 | DTCR3 = size & 0xffff; | ||
174 | SAR3 = (unsigned int) start; | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ | ||
179 | } | ||
180 | |||
181 | CHCR3 &= ~0x0002; /* Clear DMA interrupt */ | ||
182 | } | ||
183 | |||
184 | void IMIA1(void) __attribute__((interrupt_handler)); | ||
185 | void IMIA1(void) /* Timer 1 interrupt */ | ||
186 | { | ||
187 | if(playing) | ||
188 | play_tick(); | ||
189 | TSR1 &= ~0x01; | ||
190 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
191 | /* Disable interrupt */ | ||
192 | IPRC &= ~0x000f; | ||
193 | #endif | ||
194 | } | ||
195 | |||
196 | void IRQ6(void) __attribute__((interrupt_handler)); | ||
197 | void IRQ6(void) /* PB14: MAS stop demand IRQ */ | ||
198 | { | ||
199 | SCR0 &= ~0x80; | ||
200 | } | ||
201 | |||
202 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
203 | void IRQ3(void) __attribute__((interrupt_handler)); | ||
204 | void IRQ3(void) /* PA15: MAS demand IRQ */ | ||
205 | { | ||
206 | /* Begin with setting the IRQ to edge sensitive */ | ||
207 | ICR |= 0x0010; | ||
208 | |||
209 | #if CONFIG_CODEC == MAS3587F | ||
210 | if(mpeg_mode == MPEG_ENCODER) | ||
211 | rec_tick(); | ||
212 | else | ||
213 | #endif | ||
214 | postpone_dma_tick(); | ||
215 | |||
216 | /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs | ||
217 | * (invalid cross-jump optimisation) */ | ||
218 | asm volatile (""); | ||
219 | } | ||
220 | #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
221 | |||
222 | static void setup_sci0(void) | ||
223 | { | ||
224 | /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */ | ||
225 | PBCR1 = (PBCR1 & 0x0cff) | 0x1208; | ||
226 | |||
227 | /* Set PB12 to output */ | ||
228 | or_b(0x10, &PBIORH); | ||
229 | |||
230 | /* Disable serial port */ | ||
231 | SCR0 = 0x00; | ||
232 | |||
233 | /* Synchronous, no prescale */ | ||
234 | SMR0 = 0x80; | ||
235 | |||
236 | /* Set baudrate 1Mbit/s */ | ||
237 | BRR0 = 0x02; | ||
238 | |||
239 | /* use SCK as serial clock output */ | ||
240 | SCR0 = 0x01; | ||
241 | |||
242 | /* Clear FER and PER */ | ||
243 | SSR0 &= 0xe7; | ||
244 | |||
245 | /* Set interrupt ITU2 and SCI0 priority to 0 */ | ||
246 | IPRD &= 0x0ff0; | ||
247 | |||
248 | /* set PB15 and PB14 to inputs */ | ||
249 | and_b(~0x80, &PBIORH); | ||
250 | and_b(~0x40, &PBIORH); | ||
251 | |||
252 | /* Enable End of DMA interrupt at prio 8 */ | ||
253 | IPRC = (IPRC & 0xf0ff) | 0x0800; | ||
254 | |||
255 | /* Enable Tx (only!) */ | ||
256 | SCR0 |= 0x20; | ||
257 | } | ||
258 | |||
259 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
260 | static void init_playback(void) | ||
261 | { | ||
262 | unsigned long val; | ||
263 | int rc; | ||
264 | |||
265 | mp3_play_pause(false); | ||
266 | |||
267 | mas_reset(); | ||
268 | |||
269 | /* Enable the audio CODEC and the DSP core, max analog voltage range */ | ||
270 | rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); | ||
271 | if(rc < 0) | ||
272 | panicf("mas_ctrl_w: %d", rc); | ||
273 | |||
274 | /* Stop the current application */ | ||
275 | val = 0; | ||
276 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
277 | do | ||
278 | { | ||
279 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
280 | } while(val); | ||
281 | |||
282 | /* Enable the D/A Converter */ | ||
283 | shadow_codec_reg0 = 0x0001; | ||
284 | mas_codec_writereg(0x0, shadow_codec_reg0); | ||
285 | |||
286 | /* ADC scale 0%, DSP scale 100% */ | ||
287 | mas_codec_writereg(6, 0x0000); | ||
288 | mas_codec_writereg(7, 0x4000); | ||
289 | |||
290 | #ifdef HAVE_SPDIF_OUT | ||
291 | val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */ | ||
292 | #else | ||
293 | val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */ | ||
294 | #endif | ||
295 | mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1); | ||
296 | |||
297 | /* Set Demand mode and validate all settings */ | ||
298 | shadow_io_control_main = 0x25; | ||
299 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
300 | |||
301 | /* Start the Layer2/3 decoder applications */ | ||
302 | val = 0x0c; | ||
303 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
304 | do | ||
305 | { | ||
306 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
307 | } while((val & 0x0c) != 0x0c); | ||
308 | |||
309 | #if CONFIG_CODEC == MAS3587F | ||
310 | mpeg_mode = MPEG_DECODER; | ||
311 | #endif | ||
312 | |||
313 | /* set IRQ6 to edge detect */ | ||
314 | ICR |= 0x02; | ||
315 | |||
316 | /* set IRQ6 prio 8 */ | ||
317 | IPRB = ( IPRB & 0xff0f ) | 0x0080; | ||
318 | |||
319 | DEBUGF("MAS Decoding application started\n"); | ||
320 | } | ||
321 | #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
322 | |||
323 | void mp3_init(int volume, int bass, int treble, int balance, int loudness, | ||
324 | int avc, int channel_config, int stereo_width, | ||
325 | int mdb_strength, int mdb_harmonics, | ||
326 | int mdb_center, int mdb_shape, bool mdb_enable, | ||
327 | bool superbass) | ||
328 | { | ||
329 | #if CONFIG_CODEC == MAS3507D | ||
330 | unsigned long val; | ||
331 | (void)loudness; | ||
332 | (void)avc; | ||
333 | (void)mdb_strength; | ||
334 | (void)mdb_harmonics; | ||
335 | (void)mdb_center; | ||
336 | (void)mdb_shape; | ||
337 | (void)mdb_enable; | ||
338 | (void)superbass; | ||
339 | #endif | ||
340 | |||
341 | setup_sci0(); | ||
342 | |||
343 | #ifdef HAVE_MAS_SIBI_CONTROL | ||
344 | and_b(~0x01, &PBDRH); /* drive SIBI low */ | ||
345 | or_b(0x01, &PBIORH); /* output for PB8 */ | ||
346 | #endif | ||
347 | |||
348 | #if CONFIG_CODEC == MAS3507D | ||
349 | mas_reset(); | ||
350 | #elif CONFIG_CODEC == MAS3587F | ||
351 | or_b(0x08, &PAIORH); /* output for /PR */ | ||
352 | init_playback(); | ||
353 | |||
354 | mas_version_code = mas_readver(); | ||
355 | DEBUGF("MAS3587 derivate %d, version %c%d\n", | ||
356 | (mas_version_code & 0xf000) >> 12, | ||
357 | 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff); | ||
358 | #elif CONFIG_CODEC == MAS3539F | ||
359 | or_b(0x08, &PAIORH); /* output for /PR */ | ||
360 | init_playback(); | ||
361 | |||
362 | mas_version_code = mas_readver(); | ||
363 | DEBUGF("MAS3539 derivate %d, version %c%d\n", | ||
364 | (mas_version_code & 0xf000) >> 12, | ||
365 | 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff); | ||
366 | #endif | ||
367 | |||
368 | #ifdef HAVE_DAC3550A | ||
369 | dac_init(); | ||
370 | #endif | ||
371 | |||
372 | #if CONFIG_CODEC == MAS3507D | ||
373 | /* set IRQ6 to edge detect */ | ||
374 | ICR |= 0x02; | ||
375 | |||
376 | /* set IRQ6 prio 8 */ | ||
377 | IPRB = ( IPRB & 0xff0f ) | 0x0080; | ||
378 | |||
379 | mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1); | ||
380 | |||
381 | mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */ | ||
382 | mas_run(1); | ||
383 | sleep(HZ); | ||
384 | |||
385 | /* Clear the upper 12 bits of the 32-bit samples */ | ||
386 | mas_writereg(0xc5, 0); | ||
387 | mas_writereg(0xc6, 0); | ||
388 | |||
389 | /* We need to set the PLL for a 14.31818MHz crystal */ | ||
390 | if(mas_version_code == 0x0601) /* Version F10? */ | ||
391 | { | ||
392 | val = 0x5d9d0; | ||
393 | mas_writemem(MAS_BANK_D0, 0x32d, &val, 1); | ||
394 | val = 0xfffceceb; | ||
395 | mas_writemem(MAS_BANK_D0, 0x32e, &val, 1); | ||
396 | val = 0x0; | ||
397 | mas_writemem(MAS_BANK_D0, 0x32f, &val, 1); | ||
398 | mas_run(0x475); | ||
399 | } | ||
400 | else | ||
401 | { | ||
402 | val = 0x5d9d0; | ||
403 | mas_writemem(MAS_BANK_D0, 0x36d, &val, 1); | ||
404 | val = 0xfffceceb; | ||
405 | mas_writemem(MAS_BANK_D0, 0x36e, &val, 1); | ||
406 | val = 0x0; | ||
407 | mas_writemem(MAS_BANK_D0, 0x36f, &val, 1); | ||
408 | mas_run(0xfcb); | ||
409 | } | ||
410 | |||
411 | #endif | ||
412 | |||
413 | #if CONFIG_CODEC == MAS3507D | ||
414 | mas_poll_start(); | ||
415 | |||
416 | mas_writereg(MAS_REG_KPRESCALE, 0xe9400); | ||
417 | dac_enable(true); | ||
418 | #endif | ||
419 | |||
420 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
421 | ICR &= ~0x0010; /* IRQ3 level sensitive */ | ||
422 | PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */ | ||
423 | #endif | ||
424 | |||
425 | /* Must be done before calling sound_set() */ | ||
426 | audio_is_initialized = true; | ||
427 | |||
428 | sound_set(SOUND_BASS, bass); | ||
429 | sound_set(SOUND_TREBLE, treble); | ||
430 | sound_set(SOUND_BALANCE, balance); | ||
431 | sound_set(SOUND_VOLUME, volume); | ||
432 | sound_set(SOUND_CHANNELS, channel_config); | ||
433 | sound_set(SOUND_STEREO_WIDTH, stereo_width); | ||
434 | |||
435 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
436 | sound_set(SOUND_LOUDNESS, loudness); | ||
437 | sound_set(SOUND_AVC, avc); | ||
438 | sound_set(SOUND_MDB_STRENGTH, mdb_strength); | ||
439 | sound_set(SOUND_MDB_HARMONICS, mdb_harmonics); | ||
440 | sound_set(SOUND_MDB_CENTER, mdb_center); | ||
441 | sound_set(SOUND_MDB_SHAPE, mdb_shape); | ||
442 | sound_set(SOUND_MDB_ENABLE, mdb_enable); | ||
443 | sound_set(SOUND_SUPERBASS, superbass); | ||
444 | #endif | ||
445 | |||
446 | playing = false; | ||
447 | paused = true; | ||
448 | } | ||
449 | |||
450 | void mp3_shutdown(void) | ||
451 | { | ||
452 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
453 | unsigned long val = 1; | ||
454 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */ | ||
455 | #endif | ||
456 | |||
457 | #if CONFIG_CODEC == MAS3507D | ||
458 | dac_volume(0, 0, false); | ||
459 | #endif | ||
460 | } | ||
461 | |||
462 | /* new functions, to be exported to plugin API */ | ||
463 | |||
464 | void mp3_play_init(void) | ||
465 | { | ||
466 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
467 | init_playback(); | ||
468 | #endif | ||
469 | playing = false; | ||
470 | paused = true; | ||
471 | callback_for_more = NULL; | ||
472 | mp3_reset_playtime(); | ||
473 | } | ||
474 | |||
475 | void mp3_play_data(const unsigned char* start, int size, | ||
476 | void (*get_more)(unsigned char** start, size_t* size) /* callback fn */ | ||
477 | ) | ||
478 | { | ||
479 | /* init DMA */ | ||
480 | DAR3 = 0x5FFFEC3; | ||
481 | CHCR3 &= ~0x0002; /* Clear interrupt */ | ||
482 | CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */ | ||
483 | DMAOR = 0x0001; /* Enable DMA */ | ||
484 | |||
485 | callback_for_more = get_more; | ||
486 | |||
487 | SAR3 = (unsigned int)start; | ||
488 | DTCR3 = size & 0xffff; | ||
489 | |||
490 | playing = true; | ||
491 | paused = true; | ||
492 | |||
493 | CHCR3 |= 0x0001; /* Enable DMA IRQ */ | ||
494 | |||
495 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
496 | demand_irq_enable(true); | ||
497 | #endif | ||
498 | } | ||
499 | |||
500 | void mp3_play_pause(bool play) | ||
501 | { | ||
502 | if (paused && play) | ||
503 | { /* resume playback */ | ||
504 | SCR0 |= 0x80; | ||
505 | paused = false; | ||
506 | playstart_tick = current_tick; | ||
507 | } | ||
508 | else if (!paused && !play) | ||
509 | { /* stop playback */ | ||
510 | SCR0 &= 0x7f; | ||
511 | paused = true; | ||
512 | cumulative_ticks += current_tick - playstart_tick; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | bool mp3_pause_done(void) | ||
517 | { | ||
518 | unsigned long frame_count; | ||
519 | |||
520 | if (!paused) | ||
521 | return false; | ||
522 | |||
523 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1); | ||
524 | /* This works because the frame counter never wraps, | ||
525 | * i.e. zero always means lost sync. */ | ||
526 | return frame_count == 0; | ||
527 | } | ||
528 | |||
529 | void mp3_play_stop(void) | ||
530 | { | ||
531 | playing = false; | ||
532 | mp3_play_pause(false); | ||
533 | CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ | ||
534 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
535 | demand_irq_enable(false); | ||
536 | #endif | ||
537 | } | ||
538 | |||
539 | long mp3_get_playtime(void) | ||
540 | { | ||
541 | if (paused) | ||
542 | return cumulative_ticks; | ||
543 | else | ||
544 | return cumulative_ticks + current_tick - playstart_tick; | ||
545 | } | ||
546 | |||
547 | void mp3_reset_playtime(void) | ||
548 | { | ||
549 | cumulative_ticks = 0; | ||
550 | playstart_tick = current_tick; | ||
551 | } | ||
552 | |||
553 | bool mp3_is_playing(void) | ||
554 | { | ||
555 | return playing; | ||
556 | } | ||
557 | |||
558 | |||
559 | /* returns the next byte position which would be transferred */ | ||
560 | unsigned char* mp3_get_pos(void) | ||
561 | { | ||
562 | return (unsigned char*)SAR3; | ||
563 | } | ||
diff --git a/firmware/target/sh/archos/mascodec-archos.c b/firmware/target/sh/archos/mascodec-archos.c new file mode 100644 index 0000000000..3f932166eb --- /dev/null +++ b/firmware/target/sh/archos/mascodec-archos.c | |||
@@ -0,0 +1,485 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: mas.c 18807 2008-10-14 11:12:20Z zagor $ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * 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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "stdbool.h" | ||
22 | #include "config.h" | ||
23 | #include "sh7034.h" | ||
24 | #include "i2c.h" | ||
25 | #include "debug.h" | ||
26 | #include "mas35xx.h" | ||
27 | #include "kernel.h" | ||
28 | #include "system.h" | ||
29 | #include "hwcompat.h" | ||
30 | |||
31 | static int mas_devread(unsigned long *dest, int len); | ||
32 | |||
33 | int mas_default_read(unsigned short *buf) | ||
34 | { | ||
35 | unsigned char *dest = (unsigned char *)buf; | ||
36 | int ret = 0; | ||
37 | |||
38 | i2c_begin(); | ||
39 | |||
40 | i2c_start(); | ||
41 | i2c_outb(MAS_DEV_WRITE); | ||
42 | if (i2c_getack()) { | ||
43 | i2c_outb(MAS_DATA_READ); | ||
44 | if (i2c_getack()) { | ||
45 | i2c_start(); | ||
46 | i2c_outb(MAS_DEV_READ); | ||
47 | if (i2c_getack()) { | ||
48 | dest[0] = i2c_inb(0); | ||
49 | dest[1] = i2c_inb(1); | ||
50 | } | ||
51 | else | ||
52 | ret = -3; | ||
53 | } | ||
54 | else | ||
55 | ret = -2; | ||
56 | } | ||
57 | else | ||
58 | ret = -1; | ||
59 | |||
60 | i2c_stop(); | ||
61 | |||
62 | i2c_end(); | ||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | int mas_run(unsigned short address) | ||
67 | { | ||
68 | int ret = 0; | ||
69 | unsigned char buf[3]; | ||
70 | |||
71 | i2c_begin(); | ||
72 | |||
73 | buf[0] = MAS_DATA_WRITE; | ||
74 | buf[1] = address >> 8; | ||
75 | buf[2] = address & 0xff; | ||
76 | |||
77 | /* send run command */ | ||
78 | if (i2c_write(MAS_DEV_WRITE,buf,3)) | ||
79 | { | ||
80 | ret = -1; | ||
81 | } | ||
82 | |||
83 | i2c_end(); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /* note: 'len' is number of 32-bit words, not number of bytes! */ | ||
88 | int mas_readmem(int bank, int addr, unsigned long* dest, int len) | ||
89 | { | ||
90 | int ret = 0; | ||
91 | unsigned char buf[7]; | ||
92 | |||
93 | i2c_begin(); | ||
94 | |||
95 | buf[0] = MAS_DATA_WRITE; | ||
96 | buf[1] = bank?MAS_CMD_READ_D1_MEM:MAS_CMD_READ_D0_MEM; | ||
97 | buf[2] = 0x00; | ||
98 | buf[3] = (len & 0xff00) >> 8; | ||
99 | buf[4] = len & 0xff; | ||
100 | buf[5] = (addr & 0xff00) >> 8; | ||
101 | buf[6] = addr & 0xff; | ||
102 | |||
103 | /* send read command */ | ||
104 | if (i2c_write(MAS_DEV_WRITE,buf,7)) | ||
105 | { | ||
106 | ret = -1; | ||
107 | } | ||
108 | |||
109 | ret = mas_devread(dest, len); | ||
110 | |||
111 | i2c_end(); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | /* note: 'len' is number of 32-bit words, not number of bytes! */ | ||
116 | int mas_writemem(int bank, int addr, const unsigned long* src, int len) | ||
117 | { | ||
118 | int ret = 0; | ||
119 | int i, j; | ||
120 | unsigned char buf[60]; | ||
121 | const unsigned char* ptr = (const unsigned char*)src; | ||
122 | |||
123 | i2c_begin(); | ||
124 | |||
125 | i=0; | ||
126 | buf[i++] = MAS_DATA_WRITE; | ||
127 | buf[i++] = bank?MAS_CMD_WRITE_D1_MEM:MAS_CMD_WRITE_D0_MEM; | ||
128 | buf[i++] = 0x00; | ||
129 | buf[i++] = (len & 0xff00) >> 8; | ||
130 | buf[i++] = len & 0xff; | ||
131 | buf[i++] = (addr & 0xff00) >> 8; | ||
132 | buf[i++] = addr & 0xff; | ||
133 | |||
134 | j = 0; | ||
135 | while(len--) { | ||
136 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
137 | buf[i++] = 0; | ||
138 | buf[i++] = ptr[j+1]; | ||
139 | buf[i++] = ptr[j+2]; | ||
140 | buf[i++] = ptr[j+3]; | ||
141 | #else | ||
142 | buf[i++] = ptr[j+2]; | ||
143 | buf[i++] = ptr[j+3]; | ||
144 | buf[i++] = 0; | ||
145 | buf[i++] = ptr[j+1]; | ||
146 | #endif | ||
147 | j += 4; | ||
148 | } | ||
149 | |||
150 | /* send write command */ | ||
151 | if (i2c_write(MAS_DEV_WRITE,buf,i)) | ||
152 | { | ||
153 | ret = -1; | ||
154 | } | ||
155 | |||
156 | i2c_end(); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | int mas_readreg(int reg) | ||
161 | { | ||
162 | int ret = 0; | ||
163 | unsigned char buf[16]; | ||
164 | unsigned long value; | ||
165 | |||
166 | i2c_begin(); | ||
167 | |||
168 | buf[0] = MAS_DATA_WRITE; | ||
169 | buf[1] = MAS_CMD_READ_REG | (reg >> 4); | ||
170 | buf[2] = (reg & 0x0f) << 4; | ||
171 | |||
172 | /* send read command */ | ||
173 | if (i2c_write(MAS_DEV_WRITE,buf,3)) | ||
174 | { | ||
175 | ret = -1; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | if(mas_devread(&value, 1)) | ||
180 | { | ||
181 | ret = -2; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | ret = value; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | i2c_end(); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | int mas_writereg(int reg, unsigned int val) | ||
194 | { | ||
195 | int ret = 0; | ||
196 | unsigned char buf[5]; | ||
197 | |||
198 | i2c_begin(); | ||
199 | |||
200 | buf[0] = MAS_DATA_WRITE; | ||
201 | buf[1] = MAS_CMD_WRITE_REG | (reg >> 4); | ||
202 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
203 | buf[2] = ((reg & 0x0f) << 4) | (val >> 16 & 0x0f); | ||
204 | buf[3] = (val >> 8) & 0xff; | ||
205 | buf[4] = val & 0xff; | ||
206 | #else | ||
207 | buf[2] = ((reg & 0x0f) << 4) | (val & 0x0f); | ||
208 | buf[3] = (val >> 12) & 0xff; | ||
209 | buf[4] = (val >> 4) & 0xff; | ||
210 | #endif | ||
211 | |||
212 | /* send write command */ | ||
213 | if (i2c_write(MAS_DEV_WRITE,buf,5)) | ||
214 | { | ||
215 | ret = -1; | ||
216 | } | ||
217 | |||
218 | i2c_end(); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | /* note: 'len' is number of 32-bit words, not number of bytes! */ | ||
223 | static int mas_devread(unsigned long *dest, int len) | ||
224 | { | ||
225 | int ret = 0; | ||
226 | unsigned char* ptr = (unsigned char*)dest; | ||
227 | int i; | ||
228 | |||
229 | /* handle read-back */ | ||
230 | /* Remember, the MAS values are only 20 bits, so we set | ||
231 | the upper 12 bits to 0 */ | ||
232 | i2c_start(); | ||
233 | i2c_outb(MAS_DEV_WRITE); | ||
234 | if (i2c_getack()) { | ||
235 | i2c_outb(MAS_DATA_READ); | ||
236 | if (i2c_getack()) { | ||
237 | i2c_start(); | ||
238 | i2c_outb(MAS_DEV_READ); | ||
239 | if (i2c_getack()) { | ||
240 | for (i=0;len;i++) { | ||
241 | len--; | ||
242 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
243 | i2c_inb(0); /* Dummy read */ | ||
244 | ptr[i*4+0] = 0; | ||
245 | ptr[i*4+1] = i2c_inb(0) & 0x0f; | ||
246 | ptr[i*4+2] = i2c_inb(0); | ||
247 | if(len) | ||
248 | ptr[i*4+3] = i2c_inb(0); | ||
249 | else | ||
250 | ptr[i*4+3] = i2c_inb(1); /* NAK the last byte */ | ||
251 | #else | ||
252 | ptr[i*4+2] = i2c_inb(0); | ||
253 | ptr[i*4+3] = i2c_inb(0); | ||
254 | ptr[i*4+0] = i2c_inb(0); | ||
255 | if(len) | ||
256 | ptr[i*4+1] = i2c_inb(0); | ||
257 | else | ||
258 | ptr[i*4+1] = i2c_inb(1); /* NAK the last byte */ | ||
259 | #endif | ||
260 | } | ||
261 | } | ||
262 | else | ||
263 | ret = -3; | ||
264 | } | ||
265 | else | ||
266 | ret = -2; | ||
267 | } | ||
268 | else | ||
269 | ret = -1; | ||
270 | |||
271 | i2c_stop(); | ||
272 | |||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | void mas_reset(void) | ||
277 | { | ||
278 | or_b(0x01, &PAIORH); | ||
279 | |||
280 | #if CONFIG_CODEC == MAS3507D | ||
281 | /* PB5 is "MAS enable". make it GPIO output and high */ | ||
282 | PBCR2 &= ~0x0c00; | ||
283 | or_b(0x20, &PBIORL); | ||
284 | or_b(0x20, &PBDRL); | ||
285 | |||
286 | and_b(~0x01, &PADRH); | ||
287 | sleep(HZ/100); | ||
288 | or_b(0x01, &PADRH); | ||
289 | sleep(HZ/5); | ||
290 | #elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
291 | if (HW_MASK & ATA_ADDRESS_200) | ||
292 | { | ||
293 | and_b(~0x01, &PADRH); | ||
294 | sleep(HZ/100); | ||
295 | or_b(0x01, &PADRH); | ||
296 | sleep(HZ/5); | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | /* Older recorder models don't invert the POR signal */ | ||
301 | or_b(0x01, &PADRH); | ||
302 | sleep(HZ/100); | ||
303 | and_b(~0x01, &PADRH); | ||
304 | sleep(HZ/5); | ||
305 | } | ||
306 | #endif | ||
307 | } | ||
308 | |||
309 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
310 | int mas_direct_config_read(unsigned char reg) | ||
311 | { | ||
312 | int ret = 0; | ||
313 | unsigned char tmp[2]; | ||
314 | |||
315 | i2c_begin(); | ||
316 | |||
317 | i2c_start(); | ||
318 | i2c_outb(MAS_DEV_WRITE); | ||
319 | if (i2c_getack()) { | ||
320 | i2c_outb(reg); | ||
321 | if (i2c_getack()) { | ||
322 | i2c_start(); | ||
323 | i2c_outb(MAS_DEV_READ); | ||
324 | if (i2c_getack()) { | ||
325 | tmp[0] = i2c_inb(0); | ||
326 | tmp[1] = i2c_inb(1); /* NAK the last byte */ | ||
327 | ret = (tmp[0] << 8) | tmp[1]; | ||
328 | } | ||
329 | else | ||
330 | ret = -3; | ||
331 | } | ||
332 | else | ||
333 | ret = -2; | ||
334 | } | ||
335 | else | ||
336 | ret = -1; | ||
337 | |||
338 | i2c_stop(); | ||
339 | |||
340 | i2c_end(); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | int mas_direct_config_write(unsigned char reg, unsigned int val) | ||
345 | { | ||
346 | int ret = 0; | ||
347 | unsigned char buf[3]; | ||
348 | |||
349 | i2c_begin(); | ||
350 | |||
351 | buf[0] = reg; | ||
352 | buf[1] = (val >> 8) & 0xff; | ||
353 | buf[2] = val & 0xff; | ||
354 | |||
355 | /* send write command */ | ||
356 | if (i2c_write(MAS_DEV_WRITE,buf,3)) | ||
357 | { | ||
358 | ret = -1; | ||
359 | } | ||
360 | |||
361 | i2c_end(); | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | int mas_codec_writereg(int reg, unsigned int val) | ||
366 | { | ||
367 | int ret = 0; | ||
368 | unsigned char buf[5]; | ||
369 | |||
370 | i2c_begin(); | ||
371 | |||
372 | buf[0] = MAS_CODEC_WRITE; | ||
373 | buf[1] = (reg >> 8) & 0xff; | ||
374 | buf[2] = reg & 0xff; | ||
375 | buf[3] = (val >> 8) & 0xff; | ||
376 | buf[4] = val & 0xff; | ||
377 | |||
378 | /* send write command */ | ||
379 | if (i2c_write(MAS_DEV_WRITE,buf,5)) | ||
380 | { | ||
381 | ret = -1; | ||
382 | } | ||
383 | |||
384 | i2c_end(); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | int mas_codec_readreg(int reg) | ||
389 | { | ||
390 | int ret = 0; | ||
391 | unsigned char buf[16]; | ||
392 | unsigned char tmp[2]; | ||
393 | |||
394 | i2c_begin(); | ||
395 | |||
396 | buf[0] = MAS_CODEC_WRITE; | ||
397 | buf[1] = (reg >> 8) & 0xff; | ||
398 | buf[2] = reg & 0xff; | ||
399 | |||
400 | /* send read command */ | ||
401 | if (i2c_write(MAS_DEV_WRITE,buf,3)) | ||
402 | { | ||
403 | ret = -1; | ||
404 | } | ||
405 | else | ||
406 | { | ||
407 | i2c_start(); | ||
408 | i2c_outb(MAS_DEV_WRITE); | ||
409 | if (i2c_getack()) { | ||
410 | i2c_outb(MAS_CODEC_READ); | ||
411 | if (i2c_getack()) { | ||
412 | i2c_start(); | ||
413 | i2c_outb(MAS_DEV_READ); | ||
414 | if (i2c_getack()) { | ||
415 | tmp[0] = i2c_inb(0); | ||
416 | tmp[1] = i2c_inb(1); /* NAK the last byte */ | ||
417 | ret = (tmp[0] << 8) | tmp[1]; | ||
418 | } | ||
419 | else | ||
420 | ret = -4; | ||
421 | } | ||
422 | else | ||
423 | ret = -3; | ||
424 | } | ||
425 | else | ||
426 | ret = -2; | ||
427 | |||
428 | i2c_stop(); | ||
429 | } | ||
430 | |||
431 | i2c_end(); | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | unsigned long mas_readver(void) | ||
436 | { | ||
437 | int ret = 0; | ||
438 | unsigned char buf[16]; | ||
439 | unsigned long value; | ||
440 | |||
441 | i2c_begin(); | ||
442 | |||
443 | buf[0] = MAS_DATA_WRITE; | ||
444 | buf[1] = MAS_CMD_READ_IC_VER; | ||
445 | buf[2] = 0; | ||
446 | |||
447 | /* send read command */ | ||
448 | if (i2c_write(MAS_DEV_WRITE,buf,3)) | ||
449 | { | ||
450 | ret = -1; | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | if(mas_devread(&value, 1)) | ||
455 | { | ||
456 | ret = -2; | ||
457 | } | ||
458 | else | ||
459 | { | ||
460 | ret = value; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | i2c_end(); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | #endif | ||
469 | |||
470 | #if CONFIG_TUNER & S1A0903X01 | ||
471 | static int pllfreq; | ||
472 | |||
473 | void mas_store_pllfreq(int freq) | ||
474 | { | ||
475 | pllfreq = freq; | ||
476 | } | ||
477 | |||
478 | int mas_get_pllfreq(void) | ||
479 | { | ||
480 | return pllfreq; | ||
481 | } | ||
482 | #endif | ||
483 | |||
484 | |||
485 | |||