From 56c4e9fa600557242d8b78f5fd8e32c2245b76fc Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Sun, 31 Oct 2010 21:09:34 +0000 Subject: Separate mas35xx lowlevel stuff. Move SH specific bits to target tree. FS#11189 by me. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28425 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/sh/archos/audio-archos.c | 563 ++++++++++++++++++++++++++++ firmware/target/sh/archos/mascodec-archos.c | 485 ++++++++++++++++++++++++ 2 files changed, 1048 insertions(+) create mode 100644 firmware/target/sh/archos/audio-archos.c create mode 100644 firmware/target/sh/archos/mascodec-archos.c (limited to 'firmware/target/sh/archos') 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Code that has been in mpeg.c before, now creating an encapsulated play + * data module, to be used by other sources than file playback as well. + * + * Copyright (C) 2004 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include "config.h" +#include "debug.h" +#include "panic.h" +#include +#include "mp3_playback.h" +#include "sound.h" +#include "i2c.h" +#include "system.h" +#include "audiohw.h" + +/* hacking into mpeg.c, recording is still there */ +#if CONFIG_CODEC == MAS3587F +enum +{ + MPEG_DECODER, + MPEG_ENCODER +} mpeg_mode; +#endif /* #ifdef MAS3587F */ + +#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR) +extern unsigned long shadow_io_control_main; +extern unsigned shadow_codec_reg0; +#endif + +/**** globals ****/ + +/* own version, independent of mpeg.c */ +static bool paused; /* playback is paused */ +static bool playing; /* We are playing an MP3 stream */ + +/* for measuring the play time */ +static long playstart_tick; +static long cumulative_ticks; + +/* the registered callback function to ask for more mp3 data */ +static void (*callback_for_more)(unsigned char**, size_t*); + +/* list of tracks in memory */ +#define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */ +#define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1) + +bool audio_is_initialized = false; + +/* FIX: this code pretty much assumes a MAS */ + +/* dirty calls to mpeg.c */ +extern void playback_tick(void); +extern void rec_tick(void); + +unsigned long mas_version_code; + +#if CONFIG_CODEC == MAS3507D +static void mas_poll_start(void) +{ + unsigned int count; + + count = 9 * FREQ / 10000 / 8; /* 0.9 ms */ + + /* We are using timer 1 */ + + TSTR &= ~0x02; /* Stop the timer */ + TSNC &= ~0x02; /* No synchronization */ + TMDR &= ~0x02; /* Operate normally */ + + TCNT1 = 0; /* Start counting at 0 */ + GRA1 = count; + TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ + + /* Enable interrupt on level 5 */ + IPRC = (IPRC & ~0x000f) | 0x0005; + + TSR1 &= ~0x02; + TIER1 = 0xf9; /* Enable GRA match interrupt */ + + TSTR |= 0x02; /* Start timer 1 */ +} +#elif CONFIG_CODEC != SWCODEC +static void postpone_dma_tick(void) +{ + unsigned int count; + + count = 8 * FREQ / 10000 / 8; /* 0.8 ms */ + + /* We are using timer 1 */ + + TSTR &= ~0x02; /* Stop the timer */ + TSNC &= ~0x02; /* No synchronization */ + TMDR &= ~0x02; /* Operate normally */ + + TCNT1 = 0; /* Start counting at 0 */ + GRA1 = count; + TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ + + /* Enable interrupt on level 5 */ + IPRC = (IPRC & ~0x000f) | 0x0005; + + TSR1 &= ~0x02; + TIER1 = 0xf9; /* Enable GRA match interrupt */ + + TSTR |= 0x02; /* Start timer 1 */ +} +#endif + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +void demand_irq_enable(bool on) +{ + int oldlevel = disable_irq_save(); + + if(on) + { + IPRA = (IPRA & 0xfff0) | 0x000b; + ICR &= ~0x0010; /* IRQ3 level sensitive */ + } + else + IPRA &= 0xfff0; + + restore_irq(oldlevel); +} +#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ + + +static void play_tick(void) +{ + if(playing && !paused) + { + /* Start DMA if it is disabled and the DEMAND pin is high */ + if(!(SCR0 & 0x80) && (PBDR & 0x4000)) + { + SCR0 |= 0x80; + } + + playback_tick(); /* dirty call to mpeg.c */ + } +} + +void DEI3(void) __attribute__((interrupt_handler)); +void DEI3(void) +{ + unsigned char* start; + size_t size = 0; + + if (callback_for_more != NULL) + { + callback_for_more(&start, &size); + } + + if (size > 0) + { + DTCR3 = size & 0xffff; + SAR3 = (unsigned int) start; + } + else + { + CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ + } + + CHCR3 &= ~0x0002; /* Clear DMA interrupt */ +} + +void IMIA1(void) __attribute__((interrupt_handler)); +void IMIA1(void) /* Timer 1 interrupt */ +{ + if(playing) + play_tick(); + TSR1 &= ~0x01; +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + /* Disable interrupt */ + IPRC &= ~0x000f; +#endif +} + +void IRQ6(void) __attribute__((interrupt_handler)); +void IRQ6(void) /* PB14: MAS stop demand IRQ */ +{ + SCR0 &= ~0x80; +} + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +void IRQ3(void) __attribute__((interrupt_handler)); +void IRQ3(void) /* PA15: MAS demand IRQ */ +{ + /* Begin with setting the IRQ to edge sensitive */ + ICR |= 0x0010; + +#if CONFIG_CODEC == MAS3587F + if(mpeg_mode == MPEG_ENCODER) + rec_tick(); + else +#endif + postpone_dma_tick(); + + /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs + * (invalid cross-jump optimisation) */ + asm volatile (""); +} +#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ + +static void setup_sci0(void) +{ + /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */ + PBCR1 = (PBCR1 & 0x0cff) | 0x1208; + + /* Set PB12 to output */ + or_b(0x10, &PBIORH); + + /* Disable serial port */ + SCR0 = 0x00; + + /* Synchronous, no prescale */ + SMR0 = 0x80; + + /* Set baudrate 1Mbit/s */ + BRR0 = 0x02; + + /* use SCK as serial clock output */ + SCR0 = 0x01; + + /* Clear FER and PER */ + SSR0 &= 0xe7; + + /* Set interrupt ITU2 and SCI0 priority to 0 */ + IPRD &= 0x0ff0; + + /* set PB15 and PB14 to inputs */ + and_b(~0x80, &PBIORH); + and_b(~0x40, &PBIORH); + + /* Enable End of DMA interrupt at prio 8 */ + IPRC = (IPRC & 0xf0ff) | 0x0800; + + /* Enable Tx (only!) */ + SCR0 |= 0x20; +} + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +static void init_playback(void) +{ + unsigned long val; + int rc; + + mp3_play_pause(false); + + mas_reset(); + + /* Enable the audio CODEC and the DSP core, max analog voltage range */ + rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); + if(rc < 0) + panicf("mas_ctrl_w: %d", rc); + + /* Stop the current application */ + val = 0; + mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); + do + { + mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); + } while(val); + + /* Enable the D/A Converter */ + shadow_codec_reg0 = 0x0001; + mas_codec_writereg(0x0, shadow_codec_reg0); + + /* ADC scale 0%, DSP scale 100% */ + mas_codec_writereg(6, 0x0000); + mas_codec_writereg(7, 0x4000); + +#ifdef HAVE_SPDIF_OUT + val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */ +#else + val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */ +#endif + mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1); + + /* Set Demand mode and validate all settings */ + shadow_io_control_main = 0x25; + mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); + + /* Start the Layer2/3 decoder applications */ + val = 0x0c; + mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); + do + { + mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); + } while((val & 0x0c) != 0x0c); + +#if CONFIG_CODEC == MAS3587F + mpeg_mode = MPEG_DECODER; +#endif + + /* set IRQ6 to edge detect */ + ICR |= 0x02; + + /* set IRQ6 prio 8 */ + IPRB = ( IPRB & 0xff0f ) | 0x0080; + + DEBUGF("MAS Decoding application started\n"); +} +#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ + +void mp3_init(int volume, int bass, int treble, int balance, int loudness, + int avc, int channel_config, int stereo_width, + int mdb_strength, int mdb_harmonics, + int mdb_center, int mdb_shape, bool mdb_enable, + bool superbass) +{ +#if CONFIG_CODEC == MAS3507D + unsigned long val; + (void)loudness; + (void)avc; + (void)mdb_strength; + (void)mdb_harmonics; + (void)mdb_center; + (void)mdb_shape; + (void)mdb_enable; + (void)superbass; +#endif + + setup_sci0(); + +#ifdef HAVE_MAS_SIBI_CONTROL + and_b(~0x01, &PBDRH); /* drive SIBI low */ + or_b(0x01, &PBIORH); /* output for PB8 */ +#endif + +#if CONFIG_CODEC == MAS3507D + mas_reset(); +#elif CONFIG_CODEC == MAS3587F + or_b(0x08, &PAIORH); /* output for /PR */ + init_playback(); + + mas_version_code = mas_readver(); + DEBUGF("MAS3587 derivate %d, version %c%d\n", + (mas_version_code & 0xf000) >> 12, + 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff); +#elif CONFIG_CODEC == MAS3539F + or_b(0x08, &PAIORH); /* output for /PR */ + init_playback(); + + mas_version_code = mas_readver(); + DEBUGF("MAS3539 derivate %d, version %c%d\n", + (mas_version_code & 0xf000) >> 12, + 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff); +#endif + +#ifdef HAVE_DAC3550A + dac_init(); +#endif + +#if CONFIG_CODEC == MAS3507D + /* set IRQ6 to edge detect */ + ICR |= 0x02; + + /* set IRQ6 prio 8 */ + IPRB = ( IPRB & 0xff0f ) | 0x0080; + + mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1); + + mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */ + mas_run(1); + sleep(HZ); + + /* Clear the upper 12 bits of the 32-bit samples */ + mas_writereg(0xc5, 0); + mas_writereg(0xc6, 0); + + /* We need to set the PLL for a 14.31818MHz crystal */ + if(mas_version_code == 0x0601) /* Version F10? */ + { + val = 0x5d9d0; + mas_writemem(MAS_BANK_D0, 0x32d, &val, 1); + val = 0xfffceceb; + mas_writemem(MAS_BANK_D0, 0x32e, &val, 1); + val = 0x0; + mas_writemem(MAS_BANK_D0, 0x32f, &val, 1); + mas_run(0x475); + } + else + { + val = 0x5d9d0; + mas_writemem(MAS_BANK_D0, 0x36d, &val, 1); + val = 0xfffceceb; + mas_writemem(MAS_BANK_D0, 0x36e, &val, 1); + val = 0x0; + mas_writemem(MAS_BANK_D0, 0x36f, &val, 1); + mas_run(0xfcb); + } + +#endif + +#if CONFIG_CODEC == MAS3507D + mas_poll_start(); + + mas_writereg(MAS_REG_KPRESCALE, 0xe9400); + dac_enable(true); +#endif + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + ICR &= ~0x0010; /* IRQ3 level sensitive */ + PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */ +#endif + + /* Must be done before calling sound_set() */ + audio_is_initialized = true; + + sound_set(SOUND_BASS, bass); + sound_set(SOUND_TREBLE, treble); + sound_set(SOUND_BALANCE, balance); + sound_set(SOUND_VOLUME, volume); + sound_set(SOUND_CHANNELS, channel_config); + sound_set(SOUND_STEREO_WIDTH, stereo_width); + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + sound_set(SOUND_LOUDNESS, loudness); + sound_set(SOUND_AVC, avc); + sound_set(SOUND_MDB_STRENGTH, mdb_strength); + sound_set(SOUND_MDB_HARMONICS, mdb_harmonics); + sound_set(SOUND_MDB_CENTER, mdb_center); + sound_set(SOUND_MDB_SHAPE, mdb_shape); + sound_set(SOUND_MDB_ENABLE, mdb_enable); + sound_set(SOUND_SUPERBASS, superbass); +#endif + + playing = false; + paused = true; +} + +void mp3_shutdown(void) +{ +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + unsigned long val = 1; + mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */ +#endif + +#if CONFIG_CODEC == MAS3507D + dac_volume(0, 0, false); +#endif +} + +/* new functions, to be exported to plugin API */ + +void mp3_play_init(void) +{ +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + init_playback(); +#endif + playing = false; + paused = true; + callback_for_more = NULL; + mp3_reset_playtime(); +} + +void mp3_play_data(const unsigned char* start, int size, + void (*get_more)(unsigned char** start, size_t* size) /* callback fn */ +) +{ + /* init DMA */ + DAR3 = 0x5FFFEC3; + CHCR3 &= ~0x0002; /* Clear interrupt */ + CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */ + DMAOR = 0x0001; /* Enable DMA */ + + callback_for_more = get_more; + + SAR3 = (unsigned int)start; + DTCR3 = size & 0xffff; + + playing = true; + paused = true; + + CHCR3 |= 0x0001; /* Enable DMA IRQ */ + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + demand_irq_enable(true); +#endif +} + +void mp3_play_pause(bool play) +{ + if (paused && play) + { /* resume playback */ + SCR0 |= 0x80; + paused = false; + playstart_tick = current_tick; + } + else if (!paused && !play) + { /* stop playback */ + SCR0 &= 0x7f; + paused = true; + cumulative_ticks += current_tick - playstart_tick; + } +} + +bool mp3_pause_done(void) +{ + unsigned long frame_count; + + if (!paused) + return false; + + mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1); + /* This works because the frame counter never wraps, + * i.e. zero always means lost sync. */ + return frame_count == 0; +} + +void mp3_play_stop(void) +{ + playing = false; + mp3_play_pause(false); + CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + demand_irq_enable(false); +#endif +} + +long mp3_get_playtime(void) +{ + if (paused) + return cumulative_ticks; + else + return cumulative_ticks + current_tick - playstart_tick; +} + +void mp3_reset_playtime(void) +{ + cumulative_ticks = 0; + playstart_tick = current_tick; +} + +bool mp3_is_playing(void) +{ + return playing; +} + + +/* returns the next byte position which would be transferred */ +unsigned char* mp3_get_pos(void) +{ + return (unsigned char*)SAR3; +} 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: mas.c 18807 2008-10-14 11:12:20Z zagor $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "stdbool.h" +#include "config.h" +#include "sh7034.h" +#include "i2c.h" +#include "debug.h" +#include "mas35xx.h" +#include "kernel.h" +#include "system.h" +#include "hwcompat.h" + +static int mas_devread(unsigned long *dest, int len); + +int mas_default_read(unsigned short *buf) +{ + unsigned char *dest = (unsigned char *)buf; + int ret = 0; + + i2c_begin(); + + i2c_start(); + i2c_outb(MAS_DEV_WRITE); + if (i2c_getack()) { + i2c_outb(MAS_DATA_READ); + if (i2c_getack()) { + i2c_start(); + i2c_outb(MAS_DEV_READ); + if (i2c_getack()) { + dest[0] = i2c_inb(0); + dest[1] = i2c_inb(1); + } + else + ret = -3; + } + else + ret = -2; + } + else + ret = -1; + + i2c_stop(); + + i2c_end(); + return ret; +} + +int mas_run(unsigned short address) +{ + int ret = 0; + unsigned char buf[3]; + + i2c_begin(); + + buf[0] = MAS_DATA_WRITE; + buf[1] = address >> 8; + buf[2] = address & 0xff; + + /* send run command */ + if (i2c_write(MAS_DEV_WRITE,buf,3)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +/* note: 'len' is number of 32-bit words, not number of bytes! */ +int mas_readmem(int bank, int addr, unsigned long* dest, int len) +{ + int ret = 0; + unsigned char buf[7]; + + i2c_begin(); + + buf[0] = MAS_DATA_WRITE; + buf[1] = bank?MAS_CMD_READ_D1_MEM:MAS_CMD_READ_D0_MEM; + buf[2] = 0x00; + buf[3] = (len & 0xff00) >> 8; + buf[4] = len & 0xff; + buf[5] = (addr & 0xff00) >> 8; + buf[6] = addr & 0xff; + + /* send read command */ + if (i2c_write(MAS_DEV_WRITE,buf,7)) + { + ret = -1; + } + + ret = mas_devread(dest, len); + + i2c_end(); + return ret; +} + +/* note: 'len' is number of 32-bit words, not number of bytes! */ +int mas_writemem(int bank, int addr, const unsigned long* src, int len) +{ + int ret = 0; + int i, j; + unsigned char buf[60]; + const unsigned char* ptr = (const unsigned char*)src; + + i2c_begin(); + + i=0; + buf[i++] = MAS_DATA_WRITE; + buf[i++] = bank?MAS_CMD_WRITE_D1_MEM:MAS_CMD_WRITE_D0_MEM; + buf[i++] = 0x00; + buf[i++] = (len & 0xff00) >> 8; + buf[i++] = len & 0xff; + buf[i++] = (addr & 0xff00) >> 8; + buf[i++] = addr & 0xff; + + j = 0; + while(len--) { +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + buf[i++] = 0; + buf[i++] = ptr[j+1]; + buf[i++] = ptr[j+2]; + buf[i++] = ptr[j+3]; +#else + buf[i++] = ptr[j+2]; + buf[i++] = ptr[j+3]; + buf[i++] = 0; + buf[i++] = ptr[j+1]; +#endif + j += 4; + } + + /* send write command */ + if (i2c_write(MAS_DEV_WRITE,buf,i)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +int mas_readreg(int reg) +{ + int ret = 0; + unsigned char buf[16]; + unsigned long value; + + i2c_begin(); + + buf[0] = MAS_DATA_WRITE; + buf[1] = MAS_CMD_READ_REG | (reg >> 4); + buf[2] = (reg & 0x0f) << 4; + + /* send read command */ + if (i2c_write(MAS_DEV_WRITE,buf,3)) + { + ret = -1; + } + else + { + if(mas_devread(&value, 1)) + { + ret = -2; + } + else + { + ret = value; + } + } + + i2c_end(); + return ret; +} + +int mas_writereg(int reg, unsigned int val) +{ + int ret = 0; + unsigned char buf[5]; + + i2c_begin(); + + buf[0] = MAS_DATA_WRITE; + buf[1] = MAS_CMD_WRITE_REG | (reg >> 4); +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + buf[2] = ((reg & 0x0f) << 4) | (val >> 16 & 0x0f); + buf[3] = (val >> 8) & 0xff; + buf[4] = val & 0xff; +#else + buf[2] = ((reg & 0x0f) << 4) | (val & 0x0f); + buf[3] = (val >> 12) & 0xff; + buf[4] = (val >> 4) & 0xff; +#endif + + /* send write command */ + if (i2c_write(MAS_DEV_WRITE,buf,5)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +/* note: 'len' is number of 32-bit words, not number of bytes! */ +static int mas_devread(unsigned long *dest, int len) +{ + int ret = 0; + unsigned char* ptr = (unsigned char*)dest; + int i; + + /* handle read-back */ + /* Remember, the MAS values are only 20 bits, so we set + the upper 12 bits to 0 */ + i2c_start(); + i2c_outb(MAS_DEV_WRITE); + if (i2c_getack()) { + i2c_outb(MAS_DATA_READ); + if (i2c_getack()) { + i2c_start(); + i2c_outb(MAS_DEV_READ); + if (i2c_getack()) { + for (i=0;len;i++) { + len--; +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + i2c_inb(0); /* Dummy read */ + ptr[i*4+0] = 0; + ptr[i*4+1] = i2c_inb(0) & 0x0f; + ptr[i*4+2] = i2c_inb(0); + if(len) + ptr[i*4+3] = i2c_inb(0); + else + ptr[i*4+3] = i2c_inb(1); /* NAK the last byte */ +#else + ptr[i*4+2] = i2c_inb(0); + ptr[i*4+3] = i2c_inb(0); + ptr[i*4+0] = i2c_inb(0); + if(len) + ptr[i*4+1] = i2c_inb(0); + else + ptr[i*4+1] = i2c_inb(1); /* NAK the last byte */ +#endif + } + } + else + ret = -3; + } + else + ret = -2; + } + else + ret = -1; + + i2c_stop(); + + return ret; +} + +void mas_reset(void) +{ + or_b(0x01, &PAIORH); + +#if CONFIG_CODEC == MAS3507D + /* PB5 is "MAS enable". make it GPIO output and high */ + PBCR2 &= ~0x0c00; + or_b(0x20, &PBIORL); + or_b(0x20, &PBDRL); + + and_b(~0x01, &PADRH); + sleep(HZ/100); + or_b(0x01, &PADRH); + sleep(HZ/5); +#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) + if (HW_MASK & ATA_ADDRESS_200) + { + and_b(~0x01, &PADRH); + sleep(HZ/100); + or_b(0x01, &PADRH); + sleep(HZ/5); + } + else + { + /* Older recorder models don't invert the POR signal */ + or_b(0x01, &PADRH); + sleep(HZ/100); + and_b(~0x01, &PADRH); + sleep(HZ/5); + } +#endif +} + +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +int mas_direct_config_read(unsigned char reg) +{ + int ret = 0; + unsigned char tmp[2]; + + i2c_begin(); + + i2c_start(); + i2c_outb(MAS_DEV_WRITE); + if (i2c_getack()) { + i2c_outb(reg); + if (i2c_getack()) { + i2c_start(); + i2c_outb(MAS_DEV_READ); + if (i2c_getack()) { + tmp[0] = i2c_inb(0); + tmp[1] = i2c_inb(1); /* NAK the last byte */ + ret = (tmp[0] << 8) | tmp[1]; + } + else + ret = -3; + } + else + ret = -2; + } + else + ret = -1; + + i2c_stop(); + + i2c_end(); + return ret; +} + +int mas_direct_config_write(unsigned char reg, unsigned int val) +{ + int ret = 0; + unsigned char buf[3]; + + i2c_begin(); + + buf[0] = reg; + buf[1] = (val >> 8) & 0xff; + buf[2] = val & 0xff; + + /* send write command */ + if (i2c_write(MAS_DEV_WRITE,buf,3)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +int mas_codec_writereg(int reg, unsigned int val) +{ + int ret = 0; + unsigned char buf[5]; + + i2c_begin(); + + buf[0] = MAS_CODEC_WRITE; + buf[1] = (reg >> 8) & 0xff; + buf[2] = reg & 0xff; + buf[3] = (val >> 8) & 0xff; + buf[4] = val & 0xff; + + /* send write command */ + if (i2c_write(MAS_DEV_WRITE,buf,5)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +int mas_codec_readreg(int reg) +{ + int ret = 0; + unsigned char buf[16]; + unsigned char tmp[2]; + + i2c_begin(); + + buf[0] = MAS_CODEC_WRITE; + buf[1] = (reg >> 8) & 0xff; + buf[2] = reg & 0xff; + + /* send read command */ + if (i2c_write(MAS_DEV_WRITE,buf,3)) + { + ret = -1; + } + else + { + i2c_start(); + i2c_outb(MAS_DEV_WRITE); + if (i2c_getack()) { + i2c_outb(MAS_CODEC_READ); + if (i2c_getack()) { + i2c_start(); + i2c_outb(MAS_DEV_READ); + if (i2c_getack()) { + tmp[0] = i2c_inb(0); + tmp[1] = i2c_inb(1); /* NAK the last byte */ + ret = (tmp[0] << 8) | tmp[1]; + } + else + ret = -4; + } + else + ret = -3; + } + else + ret = -2; + + i2c_stop(); + } + + i2c_end(); + return ret; +} + +unsigned long mas_readver(void) +{ + int ret = 0; + unsigned char buf[16]; + unsigned long value; + + i2c_begin(); + + buf[0] = MAS_DATA_WRITE; + buf[1] = MAS_CMD_READ_IC_VER; + buf[2] = 0; + + /* send read command */ + if (i2c_write(MAS_DEV_WRITE,buf,3)) + { + ret = -1; + } + else + { + if(mas_devread(&value, 1)) + { + ret = -2; + } + else + { + ret = value; + } + } + + i2c_end(); + return ret; +} + +#endif + +#if CONFIG_TUNER & S1A0903X01 +static int pllfreq; + +void mas_store_pllfreq(int freq) +{ + pllfreq = freq; +} + +int mas_get_pllfreq(void) +{ + return pllfreq; +} +#endif + + + -- cgit v1.2.3