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 --- apps/codecs.c | 1 - apps/debug_menu.c | 1 - apps/menus/recording_menu.c | 1 - apps/mpeg.c | 4 +- apps/plugin.h | 2 +- apps/radio/radio.c | 1 - apps/recorder/peakmeter.c | 1 - apps/recorder/peakmeter.h | 1 + apps/recorder/recording.c | 1 - firmware/SOURCES | 22 +- firmware/drivers/audio/dac3550a.c | 124 ++++++ firmware/drivers/audio/mas35xx.c | 99 ++++- firmware/drivers/dac.c | 119 ------ firmware/drivers/dac.h | 48 --- firmware/drivers/mas.c | 485 ---------------------- firmware/drivers/tuner/s1a0903x01.c | 2 +- firmware/export/audiohw.h | 3 + firmware/export/dac3550a.h | 47 +++ firmware/export/mas.h | 184 --------- firmware/export/mas35xx.h | 162 +++++++- firmware/export/mascodec.h | 43 ++ firmware/mp3_playback.c | 618 ---------------------------- firmware/sound.c | 85 +--- firmware/target/sh/archos/audio-archos.c | 563 +++++++++++++++++++++++++ firmware/target/sh/archos/mascodec-archos.c | 485 ++++++++++++++++++++++ firmware/test/i2c/main.c | 4 +- uisimulator/common/stubs.c | 108 ++++- 27 files changed, 1651 insertions(+), 1563 deletions(-) create mode 100644 firmware/drivers/audio/dac3550a.c delete mode 100644 firmware/drivers/dac.c delete mode 100644 firmware/drivers/dac.h delete mode 100644 firmware/drivers/mas.c create mode 100644 firmware/export/dac3550a.h delete mode 100644 firmware/export/mas.h create mode 100644 firmware/export/mascodec.h delete mode 100644 firmware/mp3_playback.c create mode 100644 firmware/target/sh/archos/audio-archos.c create mode 100644 firmware/target/sh/archos/mascodec-archos.c diff --git a/apps/codecs.c b/apps/codecs.c index 3fa05be..88478e8 100644 --- a/apps/codecs.c +++ b/apps/codecs.c @@ -36,7 +36,6 @@ #include "kernel.h" #include "screens.h" #include "misc.h" -#include "mas.h" #include "codecs.h" #include "lang.h" #include "keyboard.h" diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 2497b17..bedc98a 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -61,7 +61,6 @@ #include "rtc.h" #include "storage.h" #include "fat.h" -#include "mas.h" #include "eeprom_24cxx.h" #if (CONFIG_STORAGE & STORAGE_MMC) || (CONFIG_STORAGE & STORAGE_SD) #include "sdmmc.h" diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c index 6a1c1d3..8eaeab6 100644 --- a/apps/menus/recording_menu.c +++ b/apps/menus/recording_menu.c @@ -49,7 +49,6 @@ #endif #ifdef HAVE_RECORDING #include "peakmeter.h" -#include "mas.h" #endif #include "splash.h" #if CONFIG_CODEC == SWCODEC diff --git a/apps/mpeg.c b/apps/mpeg.c index 62fda5e..583e4e2 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c @@ -45,7 +45,7 @@ #include "settings.h" #ifndef SIMULATOR #include "i2c.h" -#include "mas.h" +#include "mas35xx.h" #include "system.h" #include "usb.h" #include "file.h" @@ -53,7 +53,7 @@ #endif /* !SIMULATOR */ #ifdef HAVE_LCD_BITMAP #include "lcd.h" -#endif +#endif /* CONFIG_CODEC != SWCODEC */ #define MPEG_SWAP_CHUNKSIZE 0x2000 #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we diff --git a/apps/plugin.h b/apps/plugin.h index 56e0bfc..0503980 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -77,7 +77,7 @@ void* plugin_get_buffer(size_t *buffer_size); #include "recording.h" #endif #else -#include "mas.h" +#include "mas35xx.h" #endif /* CONFIG_CODEC == SWCODEC */ #include "settings.h" #include "timer.h" diff --git a/apps/radio/radio.c b/apps/radio/radio.c index 6f1903d..5fe1fab 100644 --- a/apps/radio/radio.c +++ b/apps/radio/radio.c @@ -23,7 +23,6 @@ #include #include #include -#include "mas.h" #include "settings.h" #include "button.h" #include "status.h" diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c index 2450559..aacfc23 100644 --- a/apps/recorder/peakmeter.c +++ b/apps/recorder/peakmeter.c @@ -22,7 +22,6 @@ #if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC) #include /* sim uses rand for peakmeter simulation */ #endif -#include "mas.h" #include "thread.h" #include "kernel.h" #include "settings.h" diff --git a/apps/recorder/peakmeter.h b/apps/recorder/peakmeter.h index 308e5fb..4abcc15 100644 --- a/apps/recorder/peakmeter.h +++ b/apps/recorder/peakmeter.h @@ -22,6 +22,7 @@ #define __PEAKMETER_H__ #define PEAK_METER_FPS 20 +#define MAX_PEAK 0x8000 /*#define PM_DEBUG */ #ifdef PM_DEBUG diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 9adb3c1..fdeae03 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -42,7 +42,6 @@ #include "pcm_record.h" #include "recording.h" #include "mp3_playback.h" -#include "mas.h" #include "button.h" #include "kernel.h" #include "settings.h" diff --git a/firmware/SOURCES b/firmware/SOURCES index f118f6a..5b7a582 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -175,7 +175,7 @@ drivers/led.c drivers/button.c #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #ifdef HAVE_DAC3550A -drivers/dac.c +drivers/audio/dac3550a.c #endif #ifdef HAVE_SERIAL drivers/serial.c @@ -289,9 +289,6 @@ drivers/tuner/rda5802.c #endif /* BOOTLOADER */ /* Sound */ -#if CONFIG_CODEC != SWCODEC -mp3_playback.c -#endif /* CONFIG_CODEC != SWCODEC */ sound.c #if CONFIG_CODEC == SWCODEC @@ -303,15 +300,6 @@ pcm.c enc_base.c #endif /* HAVE_RECORDING */ #endif /* BOOTLOADER */ - -#else /* !SWCODEC */ - -#ifndef BOOTLOADER -#ifndef SIMULATOR -drivers/mas.c -#endif /* SIMULATOR */ -#endif /* BOOTLOADER */ - #endif /* SWCODEC */ /* Audio codec */ @@ -574,6 +562,8 @@ target/sh/archos/player/lcd-player.c target/sh/archos/player/power-player.c target/sh/archos/player/powermgmt-player.c target/sh/archos/player/usb-player.c +target/sh/archos/mascodec-archos.c +target/sh/archos/audio-archos.c #endif /* SIMULATOR */ #endif /* ARCHOS_PLAYER */ @@ -588,6 +578,8 @@ target/sh/archos/recorder/button-recorder.c target/sh/archos/recorder/power-recorder.c target/sh/archos/recorder/powermgmt-recorder.c target/sh/archos/recorder/usb-recorder.c +target/sh/archos/mascodec-archos.c +target/sh/archos/audio-archos.c #endif /* SIMULATOR */ #endif /* ARCHOS_RECORDER */ @@ -602,6 +594,8 @@ target/sh/archos/fm_v2/button-fm_v2.c target/sh/archos/fm_v2/power-fm_v2.c target/sh/archos/fm_v2/powermgmt-fm_v2.c target/sh/archos/fm_v2/usb-fm_v2.c +target/sh/archos/mascodec-archos.c +target/sh/archos/audio-archos.c #endif /* SIMULATOR */ #endif /* ARCHOS_FMRECORDER || ARCHOS_RECORDERV2 */ @@ -614,6 +608,8 @@ target/sh/archos/ondio/button-ondio.c target/sh/archos/ondio/power-ondio.c target/sh/archos/ondio/powermgmt-ondio.c target/sh/archos/ondio/usb-ondio.c +target/sh/archos/mascodec-archos.c +target/sh/archos/audio-archos.c #if (CONFIG_TUNER & TEA5767) target/sh/archos/ondio/fmradio_i2c-ondio.c #endif diff --git a/firmware/drivers/audio/dac3550a.c b/firmware/drivers/audio/dac3550a.c new file mode 100644 index 0000000..e13602e --- /dev/null +++ b/firmware/drivers/audio/dac3550a.c @@ -0,0 +1,124 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: dac.c 17847 2008-06-28 18:10:04Z bagder $ + * + * 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 "config.h" +#include "stdbool.h" +#include "i2c.h" +#include "debug.h" +#include "dac3550a.h" + +static bool line_in_enabled = false; +static bool dac_enabled = false; + +/* convert tenth of dB volume (-780..+180) to dac3550 register value */ +int tenthdb2reg(int db) +{ + if (db < -540) /* 3 dB steps */ + return (db + 780) / 30; + else /* 1.5 dB steps */ + return (db + 660) / 15; +} + +int dac_volume(unsigned int left, unsigned int right, bool deemph) +{ + int ret = 0; + unsigned char buf[3]; + + i2c_begin(); + + if (left > 0x38) + left = 0x38; + if (right > 0x38) + right = 0x38; + + buf[0] = DAC_REG_WRITE | DAC_AVOL; + buf[1] = (left & 0x3f) | (deemph ? 0x40 : 0); + buf[2] = right & 0x3f; + + /* send write command */ + if (i2c_write(DAC_DEV_WRITE,buf,3)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +/****************************************************************** +** Bit6: 0 = 3V 1 = 5V +** Bit5: 0 = normal 1 = low power +** Bit4: 0 = AUX2 off 1 = AUX2 on +** Bit3: 0 = AUX1 off 1 = AUX1 on +** Bit2: 0 = DAC off 1 = DAC on +** Bit1: 0 = stereo 1 = mono +** Bit0: 0 = normal right amp 1 = inverted right amp +******************************************************************/ +/* dac_config is called once to initialize it. we will apply + our static settings because of the init flow. + dac_init -> dac_line_in -> mpeg_init -> dac_config +*/ +static int dac_config(void) +{ + int ret = 0; + unsigned char buf[2]; + + i2c_begin(); + + buf[0] = DAC_REG_WRITE | DAC_GCFG; + buf[1] = (dac_enabled ? 0x04 : 0) | + (line_in_enabled ? 0x08 : 0); + + /* send write command */ + if (i2c_write(DAC_DEV_WRITE,buf,2)) + { + ret = -1; + } + + i2c_end(); + return ret; +} + +void dac_enable(bool enable) +{ + dac_enabled = enable; + dac_config(); +} + +void dac_line_in(bool enable) +{ + line_in_enabled = enable; + dac_config(); +} + +void dac_init(void) +{ + unsigned char buf[2]; + + i2c_begin(); + + buf[0] = DAC_REG_WRITE | DAC_SR_REG; + buf[1] = 0x07; + + /* send write command */ + i2c_write(DAC_DEV_WRITE,buf,2); + i2c_end(); +} + diff --git a/firmware/drivers/audio/mas35xx.c b/firmware/drivers/audio/mas35xx.c index 342d8a3..e6cc665 100644 --- a/firmware/drivers/audio/mas35xx.c +++ b/firmware/drivers/audio/mas35xx.c @@ -23,8 +23,8 @@ ****************************************************************************/ #include "config.h" +#include "system.h" /* MAX MIN macros */ #include "audiohw.h" -#include "mas.h" const struct sound_settings_info audiohw_settings[] = { #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) @@ -56,10 +56,15 @@ const struct sound_settings_info audiohw_settings[] = { #endif }; - int channel_configuration = SOUND_CHAN_STEREO; int stereo_width = 100; +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +unsigned long mdb_shape_shadow = 0; +unsigned long loudness_shadow = 0; +unsigned long shadow_io_control_main; +#endif + static void set_channel_config(void) { @@ -181,13 +186,97 @@ void audiohw_set_treble(int val) } #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -void audiohw_set_volume(int val) { +void audiohw_set_volume(int val) +{ unsigned tmp = ((unsigned)(val + 115) & 0xff) << 8; mas_codec_writereg(MAS_REG_VOLUME_CONTROL, tmp); } -void audiohw_set_balance(int val) { +void audiohw_set_loudness(int value) +{ + loudness_shadow = (loudness_shadow & 0x04) | + (MAX(MIN(value * 4, 0x44), 0) << 8); + mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow); +} + +void audiohw_set_avc(int value) +{ + int tmp; + + static const uint16_t avc_vals[] = + { + (0x1 << 8) | (0x8 << 12), /* 20ms */ + (0x2 << 8) | (0x8 << 12), /* 2s */ + (0x4 << 8) | (0x8 << 12), /* 4s */ + (0x8 << 8) | (0x8 << 12), /* 8s */ + }; + switch (value) { + case 1: + case 2: + case 3: + case 4: + tmp = avc_vals[value -1]; + break; + case -1: /* turn off and then turn on again to decay quickly */ + tmp = mas_codec_readreg(MAS_REG_KAVC); + mas_codec_writereg(MAS_REG_KAVC, 0); + break; + default: /* off */ + tmp = 0; + break; + } + mas_codec_writereg(MAS_REG_KAVC, tmp); +} + +void audiohw_set_mdb_strength(int value) +{ + mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8); +} + +void audiohw_set_mdb_harmonics(int value) +{ + int tmp = value * 127 / 100; + mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8); +} + +void audiohw_set_mdb_center(int value) +{ + mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8); +} + +void audiohw_set_mdb_shape(int value) +{ + mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8); + mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow); +} + +void audiohw_set_mdb_enable(int value) +{ + mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0); + mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow); +} + +void audiohw_set_superbass(int value) +{ + loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0); + mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow); +} + +void audiohw_set_balance(int val) +{ unsigned tmp = ((unsigned)(val * 127 / 100) & 0xff) << 8; mas_codec_writereg(MAS_REG_BALANCE, tmp); } -#endif + +void audiohw_set_pitch(unsigned long val) +{ + mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1); + + /* We must tell the MAS that the frequency has changed. + * This will unfortunately cause a short silence. */ + + mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); +} + +#endif /* CONFIG_CODEC == MAS3587F || CONFIG_CODEC == MAS3539F */ + diff --git a/firmware/drivers/dac.c b/firmware/drivers/dac.c deleted file mode 100644 index f21ef9a..0000000 --- a/firmware/drivers/dac.c +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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 "config.h" -#include "stdbool.h" -#include "i2c.h" -#include "debug.h" -#include "dac.h" - -#ifdef HAVE_DAC3550A - -static bool line_in_enabled = false; -static bool dac_enabled = false; - - -int dac_volume(unsigned int left, unsigned int right, bool deemph) -{ - int ret = 0; - unsigned char buf[3]; - - i2c_begin(); - - if (left > 0x38) - left = 0x38; - if (right > 0x38) - right = 0x38; - - buf[0] = DAC_REG_WRITE | DAC_AVOL; - buf[1] = (left & 0x3f) | (deemph ? 0x40 : 0); - buf[2] = right & 0x3f; - - /* send write command */ - if (i2c_write(DAC_DEV_WRITE,buf,3)) - { - ret = -1; - } - - i2c_end(); - return ret; -} - -/****************************************************************** -** Bit6: 0 = 3V 1 = 5V -** Bit5: 0 = normal 1 = low power -** Bit4: 0 = AUX2 off 1 = AUX2 on -** Bit3: 0 = AUX1 off 1 = AUX1 on -** Bit2: 0 = DAC off 1 = DAC on -** Bit1: 0 = stereo 1 = mono -** Bit0: 0 = normal right amp 1 = inverted right amp -******************************************************************/ -/* dac_config is called once to initialize it. we will apply - our static settings because of the init flow. - dac_init -> dac_line_in -> mpeg_init -> dac_config -*/ -static int dac_config(void) -{ - int ret = 0; - unsigned char buf[2]; - - i2c_begin(); - - buf[0] = DAC_REG_WRITE | DAC_GCFG; - buf[1] = (dac_enabled ? 0x04 : 0) | - (line_in_enabled ? 0x08 : 0); - - /* send write command */ - if (i2c_write(DAC_DEV_WRITE,buf,2)) - { - ret = -1; - } - - i2c_end(); - return ret; -} - -void dac_enable(bool enable) -{ - dac_enabled = enable; - dac_config(); -} - -void dac_line_in(bool enable) -{ - line_in_enabled = enable; - dac_config(); -} - -void dac_init(void) -{ - unsigned char buf[2]; - - i2c_begin(); - - buf[0] = DAC_REG_WRITE | DAC_SR_REG; - buf[1] = 0x07; - - /* send write command */ - i2c_write(DAC_DEV_WRITE,buf,2); - i2c_end(); -} - -#endif diff --git a/firmware/drivers/dac.h b/firmware/drivers/dac.h deleted file mode 100644 index 121ce74..0000000 --- a/firmware/drivers/dac.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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. - * - ****************************************************************************/ -#ifndef _DAC_H_ -#define _DAC_H_ - -#include "config.h" - -#ifdef HAVE_DAC3550A - -/* - DAC I2C defs -*/ -#define DAC_ADR 0x9a -#define DAC_DEV_WRITE (DAC_ADR | 0x00) - -#define DAC_REG_WRITE 0xc0 - -/* registers..*/ -#define DAC_SR_REG 1 -#define DAC_AVOL 2 -#define DAC_GCFG 3 - -extern int dac_volume(unsigned int left, unsigned int right, bool deemph); -extern void dac_enable(bool enable); -extern void dac_line_in(bool enable); -extern void dac_init(void); - -#endif - -#endif diff --git a/firmware/drivers/mas.c b/firmware/drivers/mas.c deleted file mode 100644 index 4f384d3..0000000 --- a/firmware/drivers/mas.c +++ /dev/null @@ -1,485 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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 "mas.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 - - - diff --git a/firmware/drivers/tuner/s1a0903x01.c b/firmware/drivers/tuner/s1a0903x01.c index 3a417d7..2c93ebd 100644 --- a/firmware/drivers/tuner/s1a0903x01.c +++ b/firmware/drivers/tuner/s1a0903x01.c @@ -27,7 +27,7 @@ #include "tuner.h" /* tuner abstraction interface */ #include "fmradio.h" /* physical interface driver */ #include "sound.h" -#include "mas.h" +#include "mas35xx.h" #include "power.h" #define DEFAULT_IN1 0x100003 /* Mute */ diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 56f4d3d..930c671 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -59,6 +59,9 @@ #include "as3514.h" #elif defined(HAVE_MAS35XX) #include "mas35xx.h" +#if defined(HAVE_DAC3550A) +#include "dac3550a.h" +#endif /* HAVE_DAC3550A */ #elif defined(HAVE_TSC2100) #include "tsc2100.h" #elif defined(HAVE_JZ4740_CODEC) diff --git a/firmware/export/dac3550a.h b/firmware/export/dac3550a.h new file mode 100644 index 0000000..3744b22 --- /dev/null +++ b/firmware/export/dac3550a.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: dac.h 24158 2010-01-03 11:31:14Z Buschel $ + * + * 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. + * + ****************************************************************************/ +#ifndef _DAC3550A_H_ +#define _DAC3550A_H_ + +#include "config.h" + +/* + DAC I2C defs +*/ +#define DAC_ADR 0x9a +#define DAC_DEV_WRITE (DAC_ADR | 0x00) + +#define DAC_REG_WRITE 0xc0 + +/* registers..*/ +#define DAC_SR_REG 1 +#define DAC_AVOL 2 +#define DAC_GCFG 3 + +/* function prototypes */ +extern int tenthdb2reg(int db); +extern int dac_volume(unsigned int left, unsigned int right, bool deemph); +extern void dac_enable(bool enable); +extern void dac_line_in(bool enable); +extern void dac_init(void); + +#endif /* _DAC3550A_H_ */ + diff --git a/firmware/export/mas.h b/firmware/export/mas.h deleted file mode 100644 index 9cbe970..0000000 --- a/firmware/export/mas.h +++ /dev/null @@ -1,184 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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. - * - ****************************************************************************/ -#ifndef _MAS_H_ -#define _MAS_H_ - -#define MAS_BANK_D0 0 -#define MAS_BANK_D1 1 - -#define MAX_PEAK 0x8000 - -/* - MAS I2C defs -*/ -#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -#define MAS_ADR 0x3c -#define MAS_DEV_WRITE (MAS_ADR | 0x00) -#define MAS_DEV_READ (MAS_ADR | 0x01) - -#elif CONFIG_CODEC == MAS3507D -#define MAS_ADR 0x3a -#define MAS_DEV_WRITE (MAS_ADR | 0x00) -#define MAS_DEV_READ (MAS_ADR | 0x01) -#endif - -/* registers..*/ -#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -#define MAS_DATA_WRITE 0x68 -#define MAS_DATA_READ 0x69 -#define MAS_CODEC_WRITE 0x6c -#define MAS_CODEC_READ 0x6d -#define MAS_CONTROL 0x6a -#define MAS_DCCF 0x76 -#define MAS_DCFR 0x77 - -#elif CONFIG_CODEC == MAS3507D -#define MAS_DATA_WRITE 0x68 -#define MAS_DATA_READ 0x69 -#define MAS_CONTROL 0x6a -#endif - -/* - * MAS register - */ -#define MAS_REG_DCCF 0x8e -#define MAS_REG_MUTE 0xaa -#define MAS_REG_PIODATA 0xc8 -#define MAS_REG_StartUpConfig 0xe6 -#define MAS_REG_KPRESCALE 0xe7 -#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -#define MAS_REG_KMDB_SWITCH 0x21 -#define MAS_REG_KMDB_STR 0x22 -#define MAS_REG_KMDB_HAR 0x23 -#define MAS_REG_KMDB_FC 0x24 -#define MAS_REG_KLOUDNESS 0x1e -#define MAS_REG_QPEAK_L 0x0a -#define MAS_REG_QPEAK_R 0x0b -#define MAS_REG_DQPEAK_L 0x0c -#define MAS_REG_DQPEAK_R 0x0d -#define MAS_REG_VOLUME_CONTROL 0x10 -#define MAS_REG_BALANCE 0x11 -#define MAS_REG_KAVC 0x12 -#define MAS_REG_KBASS 0x14 -#define MAS_REG_KTREBLE 0x15 - -#elif CONFIG_CODEC == MAS3507D -#define MAS_REG_KBASS 0x6b -#define MAS_REG_KTREBLE 0x6f -#endif - -/* - * MAS commands - */ -#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -#define MAS_CMD_READ_ANCILLARY 0x50 -#define MAS_CMD_FAST_PRG_DL 0x60 -#define MAS_CMD_READ_IC_VER 0x70 -#define MAS_CMD_READ_REG 0xa0 -#define MAS_CMD_WRITE_REG 0xb0 -#define MAS_CMD_READ_D0_MEM 0xc0 -#define MAS_CMD_READ_D1_MEM 0xd0 -#define MAS_CMD_WRITE_D0_MEM 0xe0 -#define MAS_CMD_WRITE_D1_MEM 0xf0 - -#elif CONFIG_CODEC == MAS3507D -#define MAS_CMD_READ_ANCILLARY 0x30 -#define MAS_CMD_WRITE_REG 0x90 -#define MAS_CMD_WRITE_D0_MEM 0xa0 -#define MAS_CMD_WRITE_D1_MEM 0xb0 -#define MAS_CMD_READ_REG 0xd0 -#define MAS_CMD_READ_D0_MEM 0xe0 -#define MAS_CMD_READ_D1_MEM 0xf0 -#endif - -/* - * MAS D0 memory cells (MAS3587F / MAS3539F) - */ -#if CONFIG_CODEC == MAS3587F -#define MAS_D0_APP_SELECT 0x7f6 -#define MAS_D0_APP_RUNNING 0x7f7 -#define MAS_D0_ENCODER_CONTROL 0x7f0 -#define MAS_D0_IO_CONTROL_MAIN 0x7f1 -#define MAS_D0_INTERFACE_CONTROL 0x7f2 -#define MAS_D0_OFREQ_CONTROL 0x7f3 -#define MAS_D0_OUT_CLK_CONFIG 0x7f4 -#define MAS_D0_SPD_OUT_BITS 0x7f8 -#define MAS_D0_SOFT_MUTE 0x7f9 -#define MAS_D0_OUT_LL 0x7fc -#define MAS_D0_OUT_LR 0x7fd -#define MAS_D0_OUT_RL 0x7fe -#define MAS_D0_OUT_RR 0x7ff -#define MAS_D0_MPEG_FRAME_COUNT 0xfd0 -#define MAS_D0_MPEG_STATUS_1 0xfd1 -#define MAS_D0_MPEG_STATUS_2 0xfd2 -#define MAS_D0_CRC_ERROR_COUNT 0xfd3 - -#elif CONFIG_CODEC == MAS3539F -#define MAS_D0_APP_SELECT 0x34b -#define MAS_D0_APP_RUNNING 0x34c -/* no encoder :( */ -#define MAS_D0_IO_CONTROL_MAIN 0x346 -#define MAS_D0_INTERFACE_CONTROL 0x347 -#define MAS_D0_OFREQ_CONTROL 0x348 -#define MAS_D0_OUT_CLK_CONFIG 0x349 -#define MAS_D0_SPD_OUT_BITS 0x351 -#define MAS_D0_SOFT_MUTE 0x350 -#define MAS_D0_OUT_LL 0x354 -#define MAS_D0_OUT_LR 0x355 -#define MAS_D0_OUT_RL 0x356 -#define MAS_D0_OUT_RR 0x357 -#define MAS_D0_MPEG_FRAME_COUNT 0xfd0 -#define MAS_D0_MPEG_STATUS_1 0xfd1 -#define MAS_D0_MPEG_STATUS_2 0xfd2 -#define MAS_D0_CRC_ERROR_COUNT 0xfd3 - -#elif CONFIG_CODEC == MAS3507D -#define MAS_D0_MPEG_FRAME_COUNT 0x300 -#define MAS_D0_MPEG_STATUS_1 0x301 -#define MAS_D0_MPEG_STATUS_2 0x302 -#define MAS_D0_CRC_ERROR_COUNT 0x303 -#define MAS_D0_OUT_LL 0x7f8 -#define MAS_D0_OUT_LR 0x7f9 -#define MAS_D0_OUT_RL 0x7fa -#define MAS_D0_OUT_RR 0x7fb - -#endif - -int mas_default_read(unsigned short *buf); -int mas_run(unsigned short address); -int mas_readmem(int bank, int addr, unsigned long* dest, int len); -int mas_writemem(int bank, int addr, const unsigned long* src, int len); -int mas_readreg(int reg); -int mas_writereg(int reg, unsigned int val); -void mas_reset(void); -int mas_direct_config_read(unsigned char reg); -int mas_direct_config_write(unsigned char reg, unsigned int val); -int mas_codec_writereg(int reg, unsigned int val); -int mas_codec_readreg(int reg); -unsigned long mas_readver(void); - -#endif - -#if CONFIG_TUNER & S1A0903X01 -void mas_store_pllfreq(int freq); -int mas_get_pllfreq(void); -#endif - diff --git a/firmware/export/mas35xx.h b/firmware/export/mas35xx.h index 1c50b7f..f75658f 100644 --- a/firmware/export/mas35xx.h +++ b/firmware/export/mas35xx.h @@ -25,27 +25,55 @@ #define _MAS35XX_H #include "config.h" +#include "mascodec.h" -#if CONFIG_CODEC == MAS3507D +#define MAS_BANK_D0 0 +#define MAS_BANK_D1 1 -#define VOLUME_MIN -780 -#define VOLUME_MAX 180 -#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | PRESCALER_CAP) +/* registers common to all MAS35xx */ +#define MAS_REG_DCCF 0x8e +#define MAS_REG_MUTE 0xaa +#define MAS_REG_PIODATA 0xc8 +#define MAS_REG_StartUpConfig 0xe6 +#define MAS_REG_KPRESCALE 0xe7 -#else /* CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F */ +#if CONFIG_CODEC == MAS3507D -/* MAS3587F and MAS3539F handle clipping prevention internally so we do not need - * the prescaler -> CLIPPING_CAP - */ +/* I2C defines */ +#define MAS_ADR 0x3a +#define MAS_DEV_WRITE (MAS_ADR | 0x00) +#define MAS_DEV_READ (MAS_ADR | 0x01) -#define VOLUME_MIN -400 -#define VOLUME_MAX 600 -#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | BALANCE_CAP | CLIPPING_CAP) +/* MAS3507D registers */ +#define MAS_DATA_WRITE 0x68 +#define MAS_DATA_READ 0x69 +#define MAS_CONTROL 0x6a -#endif +#define MAS_REG_KBASS 0x6b +#define MAS_REG_KTREBLE 0x6f +/* MAS3507D commands */ +#define MAS_CMD_READ_ANCILLARY 0x30 +#define MAS_CMD_WRITE_REG 0x90 +#define MAS_CMD_WRITE_D0_MEM 0xa0 +#define MAS_CMD_WRITE_D1_MEM 0xb0 +#define MAS_CMD_READ_REG 0xd0 +#define MAS_CMD_READ_D0_MEM 0xe0 +#define MAS_CMD_READ_D1_MEM 0xf0 -#if CONFIG_CODEC == MAS3507D +/* MAS3507D D0 memmory cells */ +#define MAS_D0_MPEG_FRAME_COUNT 0x300 +#define MAS_D0_MPEG_STATUS_1 0x301 +#define MAS_D0_MPEG_STATUS_2 0x302 +#define MAS_D0_CRC_ERROR_COUNT 0x303 +#define MAS_D0_OUT_LL 0x7f8 +#define MAS_D0_OUT_LR 0x7f9 +#define MAS_D0_OUT_RL 0x7fa +#define MAS_D0_OUT_RR 0x7fb + +#define VOLUME_MIN -780 +#define VOLUME_MAX 180 +#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | PRESCALER_CAP) static const unsigned int bass_table[] = { @@ -136,6 +164,112 @@ static const unsigned int prescale_table[] = 0xe6800, /* 14dB */ 0xe9400 /* 15dB */ }; -#endif /*CONFIG_CODEC == MAS3507D*/ + +#else /* CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F */ + +/* I2C defines */ +#define MAS_ADR 0x3c +#define MAS_DEV_WRITE (MAS_ADR | 0x00) +#define MAS_DEV_READ (MAS_ADR | 0x01) + +/* MAS3587F/MAS3539F registers */ +#define MAS_DATA_WRITE 0x68 +#define MAS_DATA_READ 0x69 +#define MAS_CODEC_WRITE 0x6c +#define MAS_CODEC_READ 0x6d +#define MAS_CONTROL 0x6a +#define MAS_DCCF 0x76 +#define MAS_DCFR 0x77 + +#define MAS_REG_KMDB_SWITCH 0x21 +#define MAS_REG_KMDB_STR 0x22 +#define MAS_REG_KMDB_HAR 0x23 +#define MAS_REG_KMDB_FC 0x24 +#define MAS_REG_KLOUDNESS 0x1e +#define MAS_REG_QPEAK_L 0x0a +#define MAS_REG_QPEAK_R 0x0b +#define MAS_REG_DQPEAK_L 0x0c +#define MAS_REG_DQPEAK_R 0x0d +#define MAS_REG_VOLUME_CONTROL 0x10 +#define MAS_REG_BALANCE 0x11 +#define MAS_REG_KAVC 0x12 +#define MAS_REG_KBASS 0x14 +#define MAS_REG_KTREBLE 0x15 + +/* MAS3587F/MAS3539F commands */ +#define MAS_CMD_READ_ANCILLARY 0x50 +#define MAS_CMD_FAST_PRG_DL 0x60 +#define MAS_CMD_READ_IC_VER 0x70 +#define MAS_CMD_READ_REG 0xa0 +#define MAS_CMD_WRITE_REG 0xb0 +#define MAS_CMD_READ_D0_MEM 0xc0 +#define MAS_CMD_READ_D1_MEM 0xd0 +#define MAS_CMD_WRITE_D0_MEM 0xe0 +#define MAS_CMD_WRITE_D1_MEM 0xf0 + +/* MAS3587F D0 memory cells */ +#if CONFIG_CODEC == MAS3587F +#define MAS_D0_APP_SELECT 0x7f6 +#define MAS_D0_APP_RUNNING 0x7f7 +#define MAS_D0_ENCODER_CONTROL 0x7f0 +#define MAS_D0_IO_CONTROL_MAIN 0x7f1 +#define MAS_D0_INTERFACE_CONTROL 0x7f2 +#define MAS_D0_OFREQ_CONTROL 0x7f3 +#define MAS_D0_OUT_CLK_CONFIG 0x7f4 +#define MAS_D0_SPD_OUT_BITS 0x7f8 +#define MAS_D0_SOFT_MUTE 0x7f9 +#define MAS_D0_OUT_LL 0x7fc +#define MAS_D0_OUT_LR 0x7fd +#define MAS_D0_OUT_RL 0x7fe +#define MAS_D0_OUT_RR 0x7ff +#define MAS_D0_MPEG_FRAME_COUNT 0xfd0 +#define MAS_D0_MPEG_STATUS_1 0xfd1 +#define MAS_D0_MPEG_STATUS_2 0xfd2 +#define MAS_D0_CRC_ERROR_COUNT 0xfd3 + +/* MAS3539F D0 memory cells */ +#elif CONFIG_CODEC == MAS3539F +#define MAS_D0_APP_SELECT 0x34b +#define MAS_D0_APP_RUNNING 0x34c +/* no encoder :( */ +#define MAS_D0_IO_CONTROL_MAIN 0x346 +#define MAS_D0_INTERFACE_CONTROL 0x347 +#define MAS_D0_OFREQ_CONTROL 0x348 +#define MAS_D0_OUT_CLK_CONFIG 0x349 +#define MAS_D0_SPD_OUT_BITS 0x351 +#define MAS_D0_SOFT_MUTE 0x350 +#define MAS_D0_OUT_LL 0x354 +#define MAS_D0_OUT_LR 0x355 +#define MAS_D0_OUT_RL 0x356 +#define MAS_D0_OUT_RR 0x357 +#define MAS_D0_MPEG_FRAME_COUNT 0xfd0 +#define MAS_D0_MPEG_STATUS_1 0xfd1 +#define MAS_D0_MPEG_STATUS_2 0xfd2 +#define MAS_D0_CRC_ERROR_COUNT 0xfd3 +#endif + +/* MAS3587F and MAS3539F handle clipping prevention internally so we do not need + * the prescaler -> CLIPPING_CAP + */ + +#define VOLUME_MIN -400 +#define VOLUME_MAX 600 +#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | BALANCE_CAP | CLIPPING_CAP) + +#endif /* CONFIG_CODEC */ + +/* Function prototypes */ +#if CONFIG_CODEC == MAS3587F || CONFIG_CODEC == MAS3539F +extern void audiohw_set_loudness(int value); +extern void audiohw_set_avc(int value); +extern void audiohw_set_mdb_strength(int value); +extern void audiohw_set_mdb_harmonics(int value); +extern void audiohw_set_mdb_center(int value); +extern void audiohw_set_mdb_shape(int value); +extern void audiohw_set_mdb_enable(int value); +extern void audiohw_set_superbass(int value); +extern void audiohw_set_balance(int val); +extern void audiohw_set_pitch(unsigned long val); +#endif #endif /* _MAS35XX_H */ diff --git a/firmware/export/mascodec.h b/firmware/export/mascodec.h new file mode 100644 index 0000000..82a71e3 --- /dev/null +++ b/firmware/export/mascodec.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: mas.h 24154 2010-01-03 10:27:43Z Buschel $ + * + * 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. + * + ****************************************************************************/ +#ifndef _MASCODEC_H_ +#define _MASCODEC_H_ + +int mas_default_read(unsigned short *buf); +int mas_run(unsigned short address); +int mas_readmem(int bank, int addr, unsigned long* dest, int len); +int mas_writemem(int bank, int addr, const unsigned long* src, int len); +int mas_readreg(int reg); +int mas_writereg(int reg, unsigned int val); +void mas_reset(void); +int mas_direct_config_read(unsigned char reg); +int mas_direct_config_write(unsigned char reg, unsigned int val); +int mas_codec_writereg(int reg, unsigned int val); +int mas_codec_readreg(int reg); +unsigned long mas_readver(void); + +#endif + +#if CONFIG_TUNER & S1A0903X01 +void mas_store_pllfreq(int freq); +int mas_get_pllfreq(void); +#endif + diff --git a/firmware/mp3_playback.c b/firmware/mp3_playback.c deleted file mode 100644 index 8e19829..0000000 --- a/firmware/mp3_playback.c +++ /dev/null @@ -1,618 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * 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" -#ifndef SIMULATOR -#include "i2c.h" -#include "mas.h" -#include "dac.h" -#include "system.h" -#endif -#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 */ - -#ifndef SIMULATOR -/* 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*); -#endif /* #ifndef SIMULATOR */ - -/* 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); - -#ifndef SIMULATOR - -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) */ -#endif /* SIMULATOR */ - -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) -{ -#ifdef SIMULATOR - (void)volume; - (void)bass; - (void)treble; - (void)balance; - (void)loudness; - (void)avc; - (void)channel_config; - (void)stereo_width; - (void)mdb_strength; - (void)mdb_harmonics; - (void)mdb_center; - (void)mdb_shape; - (void)mdb_enable; - (void)superbass; - audio_is_initialized = true; -#else -#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 -#endif /* !SIMULATOR */ - - playing = false; - paused = true; -} - -void mp3_shutdown(void) -{ -#ifndef SIMULATOR -#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 - -#endif -} - -/* new functions, to be exported to plugin API */ - -#ifndef SIMULATOR - -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; -} -#else /* #ifndef SIMULATOR */ - -void mp3_play_pause(bool play) -{ - (void)play; -} -void mp3_play_stop(void) -{ -} - -unsigned char* mp3_get_pos(void) -{ - return NULL; -} - -void mp3_play_data(const unsigned char* start, int size, - void (*get_more)(unsigned char** start, size_t* size) /* callback fn */ -) -{ - (void)start; (void)size; (void)get_more; -} -#endif diff --git a/firmware/sound.c b/firmware/sound.c index bede186..82d5cdf 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -26,16 +26,17 @@ #include "logf.h" #include "system.h" #include "i2c.h" -#include "mas.h" #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #if CONFIG_CPU == PNX0101 #include "pnx0101.h" -#endif -#include "dac.h" +#endif /* CONFIG_CPU == PNX101 */ #if CONFIG_CODEC == SWCODEC #include "pcm.h" +#else /* !CONFIG_CODEC == HWCODEC */ +#include "mas35xx.h" +#include "dac3550a.h" #endif -#endif +#endif /* !SIMULATOR */ /* TODO * find a nice way to handle 1.5db steps -> see wm8751 ifdef in sound_set_bass/treble @@ -162,18 +163,6 @@ void sound_set_dsp_callback(int (*func)(int, intptr_t)) } #endif -#if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR) -/* convert tenth of dB volume (-780..+180) to dac3550 register value */ -static int tenthdb2reg(int db) -{ - if (db < -540) /* 3 dB steps */ - return (db + 780) / 30; - else /* 1.5 dB steps */ - return (db + 660) / 15; -} -#endif - - #if !defined(AUDIOHW_HAVE_CLIPPING) /* * The prescaler compensates for any kind of boosts, to prevent clipping. @@ -282,12 +271,6 @@ static void set_prescaled_volume(void) } #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */ - -#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) -static unsigned long mdb_shape_shadow = 0; -static unsigned long loudness_shadow = 0; -#endif - void sound_set_volume(int value) { if(!audio_is_initialized) @@ -620,86 +603,64 @@ void sound_set_loudness(int value) { if(!audio_is_initialized) return; - loudness_shadow = (loudness_shadow & 0x04) | - (MAX(MIN(value * 4, 0x44), 0) << 8); - mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow); + + audiohw_set_loudness(value); } void sound_set_avc(int value) { if(!audio_is_initialized) return; - int tmp; - static const uint16_t avc_vals[] = - { - (0x1 << 8) | (0x8 << 12), /* 20ms */ - (0x2 << 8) | (0x8 << 12), /* 2s */ - (0x4 << 8) | (0x8 << 12), /* 4s */ - (0x8 << 8) | (0x8 << 12), /* 8s */ - }; - switch (value) { - case 1: - case 2: - case 3: - case 4: - tmp = avc_vals[value -1]; - break; - case -1: /* turn off and then turn on again to decay quickly */ - tmp = mas_codec_readreg(MAS_REG_KAVC); - mas_codec_writereg(MAS_REG_KAVC, 0); - break; - default: /* off */ - tmp = 0; - break; - } - mas_codec_writereg(MAS_REG_KAVC, tmp); + audiohw_set_avc(value); } void sound_set_mdb_strength(int value) { if(!audio_is_initialized) return; - mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8); + + audiohw_set_mdb_strength(value); } void sound_set_mdb_harmonics(int value) { if(!audio_is_initialized) return; - int tmp = value * 127 / 100; - mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8); + + audiohw_set_mdb_harmonics(value); } void sound_set_mdb_center(int value) { if(!audio_is_initialized) return; - mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8); + + audiohw_set_mdb_center(value); } void sound_set_mdb_shape(int value) { if(!audio_is_initialized) return; - mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8); - mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow); + + audiohw_set_mdb_shape(value); } void sound_set_mdb_enable(int value) { if(!audio_is_initialized) return; - mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0); - mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow); + + audiohw_set_mdb_enable(value); } void sound_set_superbass(int value) { if(!audio_is_initialized) return; - loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0); - mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow); + + audiohw_set_superbass(value); } #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ @@ -847,11 +808,7 @@ void sound_set_pitch(int32_t pitch) /* Calculate the new (bogus) frequency */ val = 18432 * PITCH_SPEED_100 / pitch; - mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1); - - /* We must tell the MAS that the frequency has changed. - * This will unfortunately cause a short silence. */ - mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); + audiohw_set_pitch(val); last_pitch = pitch; } diff --git a/firmware/target/sh/archos/audio-archos.c b/firmware/target/sh/archos/audio-archos.c new file mode 100644 index 0000000..e2d8b6f --- /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 0000000..3f93216 --- /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 + + + diff --git a/firmware/test/i2c/main.c b/firmware/test/i2c/main.c index ad0f8ef..7a2ff49 100644 --- a/firmware/test/i2c/main.c +++ b/firmware/test/i2c/main.c @@ -46,9 +46,9 @@ #include "i2c.h" -#include "mas.h" +#include "mas35xx.h" -#include "dac.h" +#include "dac3550a.h" #include "sh7034.h" diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c index a9011b9..e0372d2 100644 --- a/uisimulator/common/stubs.c +++ b/uisimulator/common/stubs.c @@ -40,7 +40,113 @@ void audio_set_buffer_margin(int seconds) { (void)seconds; } -#endif + +/* firmware/target/sh/archos/audio-archos.c */ + +/* 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) + +static bool paused; /* playback is paused */ +static bool playing; /* We are playing an MP3 stream */ + +bool audio_is_initialized = false; + +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) +{ + (void)volume; + (void)bass; + (void)treble; + (void)balance; + (void)loudness; + (void)avc; + (void)channel_config; + (void)stereo_width; + (void)mdb_strength; + (void)mdb_harmonics; + (void)mdb_center; + (void)mdb_shape; + (void)mdb_enable; + (void)superbass; + audio_is_initialized = true; + + playing = false; + paused = true; +} + +void mp3_play_pause(bool play) +{ + (void)play; +} + +void mp3_play_stop(void) +{ +} + +unsigned char* mp3_get_pos(void) +{ + return NULL; +} + +void mp3_play_data(const unsigned char* start, int size, + void (*get_more)(unsigned char** start, size_t* size) /* callback fn */ +) +{ + (void)start; (void)size; (void)get_more; +} + +/* firmware/drivers/audio/mas35xx.c */ +#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) +void audiohw_set_loudness(int value) +{ + (void)value; +} + +void audiohw_set_avc(int value) +{ + (void)value; +} + +void audiohw_set_mdb_strength(int value) +{ + (void)value; +} + +void audiohw_set_mdb_harmonics(int value) +{ + (void)value; +} + +void audiohw_set_mdb_center(int value) +{ + (void)value; +} + +void audiohw_set_mdb_shape(int value) +{ + (void)value; +} + +void audiohw_set_mdb_enable(int value) +{ + (void)value; +} + +void audiohw_set_superbass(int value) +{ + (void)value; +} + +void audiohw_set_pitch(unsigned long value) +{ + (void)value; +} +#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ +#endif /* CODEC != SWCODEC */ int fat_startsector(void) { -- cgit v1.1