From 15dfe87f9606a191707d5c7b3b33b21963510f53 Mon Sep 17 00:00:00 2001 From: Marcoen Hirschberg Date: Thu, 19 Apr 2007 10:46:50 +0000 Subject: move audio drivers together into a subdir git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13209 a1c6a512-1295-4272-9138-f99709370657 --- firmware/FILES | 1 + firmware/SOURCES | 12 +- firmware/drivers/as3514.c | 211 ------------------ firmware/drivers/audio/as3514.c | 211 ++++++++++++++++++ firmware/drivers/audio/tlv320.c | 305 ++++++++++++++++++++++++++ firmware/drivers/audio/uda1380.c | 460 +++++++++++++++++++++++++++++++++++++++ firmware/drivers/audio/wm8731l.c | 305 ++++++++++++++++++++++++++ firmware/drivers/audio/wm8758.c | 299 +++++++++++++++++++++++++ firmware/drivers/audio/wm8975.c | 318 +++++++++++++++++++++++++++ firmware/drivers/tlv320.c | 305 -------------------------- firmware/drivers/uda1380.c | 460 --------------------------------------- firmware/drivers/wm8731l.c | 305 -------------------------- firmware/drivers/wm8758.c | 299 ------------------------- firmware/drivers/wm8975.c | 318 --------------------------- 14 files changed, 1905 insertions(+), 1904 deletions(-) delete mode 100644 firmware/drivers/as3514.c create mode 100644 firmware/drivers/audio/as3514.c create mode 100644 firmware/drivers/audio/tlv320.c create mode 100644 firmware/drivers/audio/uda1380.c create mode 100644 firmware/drivers/audio/wm8731l.c create mode 100644 firmware/drivers/audio/wm8758.c create mode 100644 firmware/drivers/audio/wm8975.c delete mode 100644 firmware/drivers/tlv320.c delete mode 100644 firmware/drivers/uda1380.c delete mode 100644 firmware/drivers/wm8731l.c delete mode 100644 firmware/drivers/wm8758.c delete mode 100644 firmware/drivers/wm8975.c diff --git a/firmware/FILES b/firmware/FILES index f68e0cbb01..8c46940f14 100644 --- a/firmware/FILES +++ b/firmware/FILES @@ -10,6 +10,7 @@ decompressor/Makefile decompressor/*.[chS] decompressor/*.lds drivers/*.[chS] +drivers/audio/*.[chS] drivers/rtc/*.[chS] export/*.h include/*.h diff --git a/firmware/SOURCES b/firmware/SOURCES index 84ff23cae2..90ec640476 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -196,17 +196,17 @@ drivers/mas.c /* Audio codec */ #ifndef SIMULATOR #if defined(HAVE_UDA1380) -drivers/uda1380.c +drivers/audio/uda1380.c #elif defined(HAVE_WM8975) || defined(HAVE_WM8751) -drivers/wm8975.c +drivers/audio/wm8975.c #elif defined(HAVE_WM8758) -drivers/wm8758.c +drivers/audio/wm8758.c #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) -drivers/wm8731l.c +drivers/audio/wm8731l.c #elif defined(HAVE_AS3514) -drivers/as3514.c +drivers/audio/as3514.c #elif defined(HAVE_TLV320) -drivers/tlv320.c +drivers/audio/tlv320.c #endif /* defined(HAVE_*) */ #endif /* SIMULATOR */ diff --git a/firmware/drivers/as3514.c b/firmware/drivers/as3514.c deleted file mode 100644 index 89761fbbe0..0000000000 --- a/firmware/drivers/as3514.c +++ /dev/null @@ -1,211 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Driver for AS3514 audio codec - * - * Copyright (c) 2007 Daniel Ankers - * Copyright (c) 2007 Christian Gmeiner - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "cpu.h" -#include "debug.h" -#include "system.h" - -#include "as3514.h" -#include "i2s.h" -#include "i2c-pp.h" - -/* Shadow registers */ -int as3514_regs[0x1D]; - -/* - * little helper method to set register values. - * With the help of as3514_regs, we minimize i2c - * traffic. - */ -static void as3514_write(int reg, int value) -{ - if (pp_i2c_send(AS3514_I2C_ADDR, reg, value) != 2) - { - DEBUGF("as3514 error reg=0x%x", reg); - } - as3514_regs[reg] = value; -} - -/* convert tenth of dB volume to master volume register value */ -int tenthdb2master(int db) -{ - /* +6 to -40.43dB in 1.5dB steps == 32 levels = 5 bits */ - /* 11111 == +6dB (0x1f) = 31) */ - /* 11110 == -4.5dB (0x1e) = 30) */ - /* 00001 == -39dB (0x01) */ - /* 00000 == -40.5dB (0x00) */ - - if (db < VOLUME_MIN) { - return 0x0; - } else if (db >= VOLUME_MAX) { - return 0x1f; - } else { - return((db-VOLUME_MIN)/15); /* VOLUME_MIN is negative */ - } -} - -void audiohw_reset(void); - -/* - * Initialise the PP I2C and I2S. - */ -int audiohw_init(void) -{ - unsigned int i; - - /* reset I2C */ - i2c_init(); - - /* normal outputs for CDI and I2S pin groups */ - DEV_INIT &= ~0x300; - - /*mini2?*/ - outl(inl(0x70000010) & ~0x3000000, 0x70000010); - /*mini2?*/ - - /* device reset */ - DEV_RS |= 0x800; - DEV_RS &=~0x800; - - /* device enable */ - DEV_EN |= 0x807; - - /* enable external dev clock clocks */ - DEV_EN |= 0x2; - - /* external dev clock to 24MHz */ - outl(inl(0x70000018) & ~0xc, 0x70000018); - - i2s_reset(); - - /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ - as3514_write(AUDIOSET1, 0x20); /* Turn on DAC */ - as3514_write(AUDIOSET3, 0x5); /* Set HPCM off, ZCU off*/ - as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */ - as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */ - as3514_write(PLLMODE, 0x04); - - /* read all reg values */ - for (i = 0; i < sizeof(as3514_regs); i++) - { - as3514_regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i); - } - - return 0; -} - -void audiohw_postinit(void) -{ -} - -/* Silently enable / disable audio output */ -void audiohw_enable_output(bool enable) -{ - int curr; - curr = as3514_regs[HPH_OUT_L]; - - if (enable) - { - /* reset the I2S controller into known state */ - i2s_reset(); - - as3514_write(HPH_OUT_L, curr | 0x40); /* power on */ - audiohw_mute(0); - } else { - audiohw_mute(1); - as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */ - } -} - -int audiohw_set_master_vol(int vol_l, int vol_r) -{ - vol_l &= 0x1f; - vol_r &= 0x1f; - - /* we are controling dac volume instead of headphone volume, - as the volume is bigger. - HDP: 1.07 dB gain - DAC: 6 dB gain - */ - as3514_write(DAC_R, vol_r); - as3514_write(DAC_L, 0x40 | vol_l); - - return 0; -} - -int audiohw_set_lineout_vol(int vol_l, int vol_r) -{ - as3514_write(LINE_OUT_R, vol_r); - as3514_write(LINE_OUT_L, 0x40 | vol_l); - - return 0; -} - -int audiohw_mute(int mute) -{ - int curr; - curr = as3514_regs[HPH_OUT_L]; - - if (mute) - { - as3514_write(HPH_OUT_L, curr | 0x80); - } else { - as3514_write(HPH_OUT_L, curr & ~(0x80)); - } - - return 0; -} - -/* Nice shutdown of WM8758 codec */ -void audiohw_close(void) -{ - /* mute headphones */ - audiohw_mute(1); - - /* turn off everything */ - as3514_write(AUDIOSET1, 0x0); -} - -void audiohw_set_sample_rate(int sampling_control) -{ - (void)sampling_control; -} - -void audiohw_enable_recording(bool source_mic) -{ - (void)source_mic; -} - -void audiohw_disable_recording(void) -{ -} - -void audiohw_set_recvol(int left, int right, int type) -{ - (void)left; - (void)right; - (void)type; -} - -void audiohw_set_monitor(int enable) -{ - (void)enable; -} diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c new file mode 100644 index 0000000000..89761fbbe0 --- /dev/null +++ b/firmware/drivers/audio/as3514.c @@ -0,0 +1,211 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for AS3514 audio codec + * + * Copyright (c) 2007 Daniel Ankers + * Copyright (c) 2007 Christian Gmeiner + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "cpu.h" +#include "debug.h" +#include "system.h" + +#include "as3514.h" +#include "i2s.h" +#include "i2c-pp.h" + +/* Shadow registers */ +int as3514_regs[0x1D]; + +/* + * little helper method to set register values. + * With the help of as3514_regs, we minimize i2c + * traffic. + */ +static void as3514_write(int reg, int value) +{ + if (pp_i2c_send(AS3514_I2C_ADDR, reg, value) != 2) + { + DEBUGF("as3514 error reg=0x%x", reg); + } + as3514_regs[reg] = value; +} + +/* convert tenth of dB volume to master volume register value */ +int tenthdb2master(int db) +{ + /* +6 to -40.43dB in 1.5dB steps == 32 levels = 5 bits */ + /* 11111 == +6dB (0x1f) = 31) */ + /* 11110 == -4.5dB (0x1e) = 30) */ + /* 00001 == -39dB (0x01) */ + /* 00000 == -40.5dB (0x00) */ + + if (db < VOLUME_MIN) { + return 0x0; + } else if (db >= VOLUME_MAX) { + return 0x1f; + } else { + return((db-VOLUME_MIN)/15); /* VOLUME_MIN is negative */ + } +} + +void audiohw_reset(void); + +/* + * Initialise the PP I2C and I2S. + */ +int audiohw_init(void) +{ + unsigned int i; + + /* reset I2C */ + i2c_init(); + + /* normal outputs for CDI and I2S pin groups */ + DEV_INIT &= ~0x300; + + /*mini2?*/ + outl(inl(0x70000010) & ~0x3000000, 0x70000010); + /*mini2?*/ + + /* device reset */ + DEV_RS |= 0x800; + DEV_RS &=~0x800; + + /* device enable */ + DEV_EN |= 0x807; + + /* enable external dev clock clocks */ + DEV_EN |= 0x2; + + /* external dev clock to 24MHz */ + outl(inl(0x70000018) & ~0xc, 0x70000018); + + i2s_reset(); + + /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ + as3514_write(AUDIOSET1, 0x20); /* Turn on DAC */ + as3514_write(AUDIOSET3, 0x5); /* Set HPCM off, ZCU off*/ + as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */ + as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */ + as3514_write(PLLMODE, 0x04); + + /* read all reg values */ + for (i = 0; i < sizeof(as3514_regs); i++) + { + as3514_regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i); + } + + return 0; +} + +void audiohw_postinit(void) +{ +} + +/* Silently enable / disable audio output */ +void audiohw_enable_output(bool enable) +{ + int curr; + curr = as3514_regs[HPH_OUT_L]; + + if (enable) + { + /* reset the I2S controller into known state */ + i2s_reset(); + + as3514_write(HPH_OUT_L, curr | 0x40); /* power on */ + audiohw_mute(0); + } else { + audiohw_mute(1); + as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */ + } +} + +int audiohw_set_master_vol(int vol_l, int vol_r) +{ + vol_l &= 0x1f; + vol_r &= 0x1f; + + /* we are controling dac volume instead of headphone volume, + as the volume is bigger. + HDP: 1.07 dB gain + DAC: 6 dB gain + */ + as3514_write(DAC_R, vol_r); + as3514_write(DAC_L, 0x40 | vol_l); + + return 0; +} + +int audiohw_set_lineout_vol(int vol_l, int vol_r) +{ + as3514_write(LINE_OUT_R, vol_r); + as3514_write(LINE_OUT_L, 0x40 | vol_l); + + return 0; +} + +int audiohw_mute(int mute) +{ + int curr; + curr = as3514_regs[HPH_OUT_L]; + + if (mute) + { + as3514_write(HPH_OUT_L, curr | 0x80); + } else { + as3514_write(HPH_OUT_L, curr & ~(0x80)); + } + + return 0; +} + +/* Nice shutdown of WM8758 codec */ +void audiohw_close(void) +{ + /* mute headphones */ + audiohw_mute(1); + + /* turn off everything */ + as3514_write(AUDIOSET1, 0x0); +} + +void audiohw_set_sample_rate(int sampling_control) +{ + (void)sampling_control; +} + +void audiohw_enable_recording(bool source_mic) +{ + (void)source_mic; +} + +void audiohw_disable_recording(void) +{ +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_monitor(int enable) +{ + (void)enable; +} diff --git a/firmware/drivers/audio/tlv320.c b/firmware/drivers/audio/tlv320.c new file mode 100644 index 0000000000..3e27d22817 --- /dev/null +++ b/firmware/drivers/audio/tlv320.c @@ -0,0 +1,305 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Christian Gmeiner + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "logf.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" + +#include "i2c-coldfire.h" +#include "tlv320.h" + +/* convert tenth of dB volume (-840..0) to master volume register value */ +int tenthdb2master(int db) +{ + /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ + /* 1111111 == +6dB (0x7f) */ + /* 1111001 == 0dB (0x79) */ + /* 0110000 == -73dB (0x30 */ + /* 0101111 == mute (0x2f) */ + + if (db < VOLUME_MIN) { + return 0x2f; + } else { + return((db/10)+73+0x30); + } +} + +/* local functions and definations */ +#define TLV320_ADDR 0x34 + +struct tlv320_info +{ + int vol_l; + int vol_r; +} tlv320; + +/* Shadow registers */ +unsigned tlv320_regs[0xf]; + +void tlv320_write_reg(unsigned reg, unsigned value) +{ + unsigned char data[2]; + + /* The register address is the high 7 bits and the data the low 9 bits */ + data[0] = (reg << 1) | ((value >> 8) & 1); + data[1] = value; + + if (i2c_write(I2C_IFACE_0, TLV320_ADDR, data, 2) != 2) + { + logf("tlv320 error reg=0x%x", reg); + return; + } + + tlv320_regs[reg] = value; +} + +/* public functions */ + +/** + * Init our tlv with default values + */ +void audiohw_init(void) +{ + memset(tlv320_regs, 0, sizeof(tlv320_regs)); + + /* Initialize all registers */ + + /* All ON except OUT, ADC, MIC and LINE */ + tlv320_write_reg(REG_PC, PC_OUT | PC_ADC | PC_MIC | PC_LINE); + audiohw_set_recvol(0, 0, AUDIO_GAIN_MIC); + audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN); + audiohw_mute(true); + tlv320_write_reg(REG_AAP, AAP_DAC | AAP_MICM); + tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ + tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); + tlv320_write_reg(REG_DIA, DIA_ACT); + audiohw_set_frequency(-1); /* default */ +} + +/** + * Switch outputs ON + */ +void audiohw_postinit(void) +{ + /* All ON except ADC, MIC and LINE */ + sleep(HZ); + tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); + sleep(HZ/4); + audiohw_mute(false); +} + +/** + * Resets tlv320 to default values + */ +void audiohw_reset(void) +{ + tlv320_write_reg(REG_RR, RR_RESET); +} + +/** + * Sets internal sample rate for DAC and ADC relative to MCLK + * Selection for frequency: + * Fs: tlv: with: + * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 + * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 + * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) + * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 + */ +void audiohw_set_frequency(unsigned fsel) +{ + /* All rates available for 11.2896MHz besides 8.021 */ + unsigned char values_src[3] = + { + /* Fs: */ + (0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */ + (0x8 << 2), /* 44100 */ + (0xf << 2), /* 88200 */ + }; + + unsigned value_dap, value_pc; + + if (fsel >= ARRAYLEN(values_src)) + fsel = 1; + + /* Temporarily turn off the DAC and ADC before switching sample + rates or they don't choose their filters correctly */ + value_dap = tlv320_regs[REG_DAP]; + value_pc = tlv320_regs[REG_PC]; + + tlv320_write_reg(REG_DAP, value_dap | DAP_DACM); + tlv320_write_reg(REG_PC, value_pc | PC_DAC | PC_ADC); + tlv320_write_reg(REG_SRC, values_src[fsel]); + tlv320_write_reg(REG_PC, value_pc | PC_DAC); + tlv320_write_reg(REG_PC, value_pc); + tlv320_write_reg(REG_DAP, value_dap); +} + +/** + * Sets left and right headphone volume + * + * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB + */ +void audiohw_set_headphone_vol(int vol_l, int vol_r) +{ + unsigned value_dap = tlv320_regs[REG_DAP]; + unsigned value_dap_last = value_dap; + unsigned value_l = LHV_LHV(vol_l); + unsigned value_r = RHV_RHV(vol_r); + + /* keep track of current setting */ + tlv320.vol_l = vol_l; + tlv320.vol_r = vol_r; + + if (value_l > HEADPHONE_MUTE || value_r > HEADPHONE_MUTE) + value_dap &= ~DAP_DACM; + else + value_dap |= DAP_DACM; + + /* update */ + tlv320_write_reg(REG_LHV, LHV_LZC | value_l); + tlv320_write_reg(REG_RHV, RHV_RZC | value_r); + if (value_dap != value_dap_last) + tlv320_write_reg(REG_DAP, value_dap); +} + +/** + * Set recording volume + * + * Line in : 0 .. 31 => Volume -34.5 .. +12 dB + * Mic (left): 0 .. 1 => Volume +0, +20 dB + * + */ +void audiohw_set_recvol(int left, int right, int type) +{ + if (type == AUDIO_GAIN_MIC) + { + unsigned value_aap = tlv320_regs[REG_AAP]; + + if (left) + value_aap |= AAP_MICB; /* Enable mic boost (20dB) */ + else + value_aap &= ~AAP_MICB; + + tlv320_write_reg(REG_AAP, value_aap); + } + else if (type == AUDIO_GAIN_LINEIN) + { + tlv320_write_reg(REG_LLIV, LLIV_LIV(left)); + tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); + } +} + +/** + * Mute (mute=true) or enable sound (mute=false) + * + */ +void audiohw_mute(bool mute) +{ + unsigned value_dap = tlv320_regs[REG_DAP]; + unsigned value_l, value_r; + + if (mute) + { + value_l = LHV_LHV(HEADPHONE_MUTE); + value_r = RHV_RHV(HEADPHONE_MUTE); + value_dap |= DAP_DACM; + } + else + { + value_l = LHV_LHV(tlv320.vol_l); + value_r = RHV_RHV(tlv320.vol_r); + if (value_l > HEADPHONE_MUTE || value_r > HEADPHONE_MUTE) + value_dap &= ~DAP_DACM; + } + + tlv320_write_reg(REG_LHV, LHV_LZC | value_l); + tlv320_write_reg(REG_RHV, RHV_RZC | value_r); + tlv320_write_reg(REG_DAP, value_dap); +} + +/* Nice shutdown of TLV320 codec */ +void audiohw_close(void) +{ + audiohw_mute(true); + sleep(HZ/8); + + tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | + PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ +} + +void audiohw_enable_recording(bool source_mic) +{ + unsigned value_aap, value_pc; + + if (source_mic) + { + /* select MIC and enable mic boost (20 dB) */ + value_aap = AAP_DAC | AAP_INSEL | AAP_MICB; + value_pc = PC_LINE; /* power down LINE */ + } + else + { + value_aap = AAP_DAC | AAP_MICM; + value_pc = PC_MIC; /* power down MIC */ + } + + tlv320_write_reg(REG_PC, value_pc); + tlv320_write_reg(REG_AAP, value_aap); +} + +void audiohw_disable_recording(void) +{ + unsigned value_pc = tlv320_regs[REG_PC]; + unsigned value_aap = tlv320_regs[REG_AAP]; + + value_aap |= AAP_MICM; /* mute MIC */ + tlv320_write_reg(REG_PC, value_aap); + + value_pc |= PC_ADC | PC_MIC | PC_LINE; /* ADC, MIC and LINE off */ + tlv320_write_reg(REG_PC, value_pc); +} + +void audiohw_set_monitor(bool enable) +{ + unsigned value_aap, value_pc; + + if (enable) + { + /* Keep DAC on to allow mixing of voice with analog audio */ + value_aap = AAP_DAC | AAP_BYPASS | AAP_MICM; + value_pc = PC_ADC | PC_MIC; /* ADC and MIC off */ + } + else + { + value_aap = AAP_DAC | AAP_MICM; + value_pc = PC_ADC | PC_MIC | PC_LINE; /* ADC, MIC and LINE off */ + } + + tlv320_write_reg(REG_AAP, value_aap); + tlv320_write_reg(REG_PC, value_pc); +} diff --git a/firmware/drivers/audio/uda1380.c b/firmware/drivers/audio/uda1380.c new file mode 100644 index 0000000000..6984427fc9 --- /dev/null +++ b/firmware/drivers/audio/uda1380.c @@ -0,0 +1,460 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Andy Young + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "debug.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" +#include "logf.h" + +#include "i2c-coldfire.h" +#include "uda1380.h" +#include "pcf50606.h" + +/* convert tenth of dB volume (-840..0) to master volume register value */ +int tenthdb2master(int db) +{ + if (db < -720) /* 1.5 dB steps */ + return (2940 - db) / 15; + else if (db < -660) /* 0.75 dB steps */ + return (1110 - db) * 2 / 15; + else if (db < -520) /* 0.5 dB steps */ + return (520 - db) / 5; + else /* 0.25 dB steps */ + return -db * 2 / 5; +} + +/* convert tenth of dB volume (-780..0) to mixer volume register value */ +int tenthdb2mixer(int db) +{ + if (db < -660) /* 1.5 dB steps */ + return (2640 - db) / 15; + else if (db < -600) /* 0.75 dB steps */ + return (990 - db) * 2 / 15; + else if (db < -460) /* 0.5 dB steps */ + return (460 - db) / 5; + else /* 0.25 dB steps */ + return -db * 2 / 5; +} + +/* ------------------------------------------------- */ +/* Local functions and variables */ +/* ------------------------------------------------- */ + +int uda1380_write_reg(unsigned char reg, unsigned short value); +unsigned short uda1380_regs[0x30]; +short recgain_mic; +short recgain_line; + +/* Definition of a playback configuration to start with */ + +#define NUM_DEFAULT_REGS 13 +unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = +{ + REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK | + SYSCLK_256FS | WSPLL_25_50, + REG_I2S, I2S_IFMT_IIS, + REG_PWR, PON_PLL | PON_BIAS, + /* PON_HP & PON_DAC is enabled later */ + REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), + /* 00=max, 3f=mute */ + REG_MASTER_VOL, MASTER_VOL_LEFT(0x20) | MASTER_VOL_RIGHT(0x20), + /* 00=max, ff=mute */ + REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), + /* 00=max, ff=mute */ + REG_EQ, EQ_MODE_MAX, + /* Bass and treble = 0 dB */ + REG_MUTE, MUTE_MASTER | MUTE_CH2, + /* Mute everything to start with */ + REG_MIX_CTL, MIX_CTL_MIX, + /* Enable mixer */ + REG_DEC_VOL, 0, + REG_PGA, MUTE_ADC, + REG_ADC, SKIP_DCFIL, + REG_AGC, 0 +}; + + + +/* Returns 0 if register was written or -1 if write failed */ +int uda1380_write_reg(unsigned char reg, unsigned short value) +{ + unsigned char data[3]; + + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0xff; + + if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 3) != 3) + { + DEBUGF("uda1380 error reg=0x%x", reg); + return -1; + } + + uda1380_regs[reg] = value; + + return 0; +} + +/** + * Sets left and right master volume (0(max) to 252(muted)) + */ +int audiohw_set_master_vol(int vol_l, int vol_r) +{ + return uda1380_write_reg(REG_MASTER_VOL, + MASTER_VOL_LEFT(vol_l) | MASTER_VOL_RIGHT(vol_r)); +} + +/** + * Sets mixer volume for both channels (0(max) to 228(muted)) + */ +int audiohw_set_mixer_vol(int channel1, int channel2) +{ + return uda1380_write_reg(REG_MIX_VOL, + MIX_VOL_CH_1(channel1) | MIX_VOL_CH_2(channel2)); +} + +/** + * Sets the bass value (0-12) + */ +void audiohw_set_bass(int value) +{ + uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~BASS_MASK) + | BASSL(value) | BASSR(value)); +} + +/** + * Sets the treble value (0-3) + */ +void audiohw_set_treble(int value) +{ + uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~TREBLE_MASK) + | TREBLEL(value) | TREBLER(value)); +} + +/** + * Mute (mute=1) or enable sound (mute=0) + * + */ +int audiohw_mute(int mute) +{ + unsigned int value = uda1380_regs[REG_MUTE]; + + if (mute) + value = value | MUTE_MASTER; + else + value = value & ~MUTE_MASTER; + + return uda1380_write_reg(REG_MUTE, value); +} + +/* Returns 0 if successful or -1 if some register failed */ +int audiohw_set_regs(void) +{ + int i; + memset(uda1380_regs, 0, sizeof(uda1380_regs)); + + /* Initialize all registers */ + for (i=0; i= ARRAYLEN(values_reg)) + fsel = 2; + + ent = values_reg[fsel]; + + /* Set WSPLL input frequency range or SYSCLK divider */ + uda1380_regs[REG_0] &= ~0xf; + uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]); + + /* Choose 3rd order or 5th order noise shaper */ + uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS; + uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]); +} + +/* Initialize UDA1380 codec with default register values (uda1380_defaults) */ +int audiohw_init(void) +{ + recgain_mic = 0; + recgain_line = 0; + + audiohw_reset(); + + if (audiohw_set_regs() == -1) + return -1; + + return 0; +} + +void audiohw_postinit(void) +{ + /* Sleep a while so the power can stabilize (especially a long + delay is needed for the line out connector). */ + sleep(HZ); + /* Power on FSDAC and HP amp. */ + audiohw_enable_output(true); + + /* UDA1380: Unmute the master channel + (DAC should be at zero point now). */ + audiohw_mute(false); +} + +/* Nice shutdown of UDA1380 codec */ +void audiohw_close(void) +{ + /* First enable mute and sleep a while */ + uda1380_write_reg(REG_MUTE, MUTE_MASTER); + sleep(HZ/8); + + /* Then power off the rest of the chip */ + uda1380_write_reg(REG_PWR, 0); + uda1380_write_reg(REG_0, 0); /* Disable codec */ +} + +/** + * Calling this function enables the UDA1380 to send + * sound samples over the I2S bus, which is connected + * to the processor's IIS1 interface. + * + * source_mic: true=record from microphone, false=record from line-in (or radio) + */ +void audiohw_enable_recording(bool source_mic) +{ + uda1380_regs[REG_0] &= ~(ADC_CLK | DAC_CLK); + uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); + + if (source_mic) + { + /* VGA_GAIN: 0=0 dB, F=30dB */ + /* Output of left ADC is fed into right bitstream */ + uda1380_regs[REG_PWR] &= ~(PON_PGAR | PON_ADCR); + uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); + uda1380_regs[REG_ADC] &= ~SKIP_DCFIL; + uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) + | SEL_LNA | SEL_MIC | EN_DCFIL); + uda1380_write_reg(REG_PGA, 0); + } + else + { + /* PGA_GAIN: 0=0 dB, F=24dB */ + uda1380_regs[REG_PWR] &= ~PON_LNA; + uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL + | PON_PGAR | PON_ADCR); + uda1380_write_reg(REG_ADC, EN_DCFIL); + uda1380_write_reg(REG_PGA, uda1380_regs[REG_PGA] & PGA_GAIN_MASK); + } + + sleep(HZ/8); + + uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); + uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); +} + +/** + * Stop sending samples on the I2S bus + */ +void audiohw_disable_recording(void) +{ + uda1380_write_reg(REG_PGA, MUTE_ADC); + sleep(HZ/8); + + uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); + + uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | + PON_PGAL | PON_PGAR); + uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR]); + + uda1380_regs[REG_0] &= ~EN_ADC; + uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ADC_CLK | DAC_CLK); + + uda1380_write_reg(REG_ADC, SKIP_DCFIL); +} + +/** + * Set recording gain and volume + * + * type: params: ranges: + * AUDIO_GAIN_MIC: left -128 .. 108 -> -64 .. 54 dB gain + * AUDIO_GAIN_LINEIN left & right -128 .. 96 -> -64 .. 48 dB gain + * + * Note: - For all types the value 0 gives 0 dB gain. + * - order of setting both values determines if the small glitch will + be a peak or a dip. The small glitch is caused by the time between + setting the two gains + */ +void audiohw_set_recvol(int left, int right, int type) +{ + int left_ag, right_ag; + + switch (type) + { + case AUDIO_GAIN_MIC: + left_ag = MIN(MAX(0, left / 4), 15); + left -= left_ag * 4; + + if(left < recgain_mic) + { + uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) + | DEC_VOLR(left)); + uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] + & ~VGA_GAIN_MASK) + | VGA_GAIN(left_ag)); + } + else + { + uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] + & ~VGA_GAIN_MASK) + | VGA_GAIN(left_ag)); + uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) + | DEC_VOLR(left)); + } + recgain_mic = left; + logf("Mic: %dA/%dD", left_ag, left); + break; + + case AUDIO_GAIN_LINEIN: + left_ag = MIN(MAX(0, left / 6), 8); + left -= left_ag * 6; + right_ag = MIN(MAX(0, right / 6), 8); + right -= right_ag * 6; + + if(left < recgain_line) + { + /* for this order we can combine both registers, + making the glitch even smaller */ + unsigned char data[5]; + unsigned short value_dec; + unsigned short value_pga; + value_dec = DEC_VOLL(left) | DEC_VOLR(right); + value_pga = (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) + | PGA_GAINL(left_ag) | PGA_GAINR(right_ag); + + data[0] = REG_DEC_VOL; + data[1] = value_dec >> 8; + data[2] = value_dec & 0xff; + data[3] = value_pga >> 8; + data[4] = value_pga & 0xff; + + if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 5) != 5) + { + DEBUGF("uda1380 error reg=combi rec gain"); + } + else + { + uda1380_regs[REG_DEC_VOL] = value_dec; + uda1380_regs[REG_PGA] = value_pga; + } + } + else + { + uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] + & ~PGA_GAIN_MASK) + | PGA_GAINL(left_ag) + | PGA_GAINR(right_ag)); + uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) + | DEC_VOLR(right)); + } + + recgain_line = left; + logf("Line L: %dA/%dD", left_ag, left); + logf("Line R: %dA/%dD", right_ag, right); + break; + } +} + + +/** + * Enable or disable recording monitor (so one can listen to the recording) + * + */ +void audiohw_set_monitor(int enable) +{ + if (enable) /* enable channel 2 */ + uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] & ~MUTE_CH2); + else /* mute channel 2 */ + uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); +} diff --git a/firmware/drivers/audio/wm8731l.c b/firmware/drivers/audio/wm8731l.c new file mode 100644 index 0000000000..62b1b6a81e --- /dev/null +++ b/firmware/drivers/audio/wm8731l.c @@ -0,0 +1,305 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for WM8731L audio codec + * + * Based on code from the ipodlinux project - http://ipodlinux.org/ + * Adapted for Rockbox in January 2006 + * + * Original file: linux/arch/armnommu/mach-ipod/audio.c + * + * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "debug.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" + +#include "wmcodec.h" +#include "wm8731l.h" +#include "i2s.h" + +#define IPOD_PCM_LEVEL 0x65 /* -6dB */ + +/* use zero crossing to reduce clicks during volume changes */ +#define VOLUME_ZC_WAIT (1<<7) + +/* convert tenth of dB volume (-730..60) to master volume register value */ +int tenthdb2master(int db) +{ + /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ + /* 1111111 == +6dB (0x7f) */ + /* 1111001 == 0dB (0x79) */ + /* 0110000 == -73dB (0x30 */ + /* 0101111 == mute (0x2f) */ + + if (db < VOLUME_MIN) { + return 0x2f; + } else { + return((db/10)+0x30+73); + } +} + +/* convert tenth of dB volume (-780..0) to mixer volume register value */ +int tenthdb2mixer(int db) +{ + if (db < -660) /* 1.5 dB steps */ + return (2640 - db) / 15; + else if (db < -600) /* 0.75 dB steps */ + return (990 - db) * 2 / 15; + else if (db < -460) /* 0.5 dB steps */ + return (460 - db) / 5; + else /* 0.25 dB steps */ + return -db * 2 / 5; +} + +int audiohw_mute(int mute) +{ + if (mute) + { + /* Set DACMU = 1 to soft-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x8); + } else { + /* Set DACMU = 0 to soft-un-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x0); + } + + return 0; +} + +/** From ipodLinux **/ +static void codec_set_active(int active) +{ + /* set active to 0x0 or 0x1 */ + if (active) { + wmcodec_write(ACTIVECTRL, 0x01); + } else { + wmcodec_write(ACTIVECTRL, 0x00); + } +} + + +/* Silently enable / disable audio output */ +void audiohw_enable_output(bool enable) +{ + if (enable) + { + /* reset the I2S controller into known state */ + i2s_reset(); + + wmcodec_write(RESET, 0x0); /*Reset*/ + + codec_set_active(0x0); + +#ifdef HAVE_WM8721 + /* DACSEL=1 */ + wmcodec_write(0x4, 0x10); +#elif defined HAVE_WM8731 + /* DACSEL=1, BYPASS=1 */ + wmcodec_write(0x4, 0x18); +#endif + + /* set power register to POWEROFF=0 on OUTPD=0, DACPD=0 */ + wmcodec_write(PWRMGMT, 0x67); + + /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ + /* IWL=00(16 bit) FORMAT=10(I2S format) */ + wmcodec_write(AINTFCE, 0x42); + + audiohw_set_sample_rate(WM8731L_44100HZ); + + /* set the volume to -6dB */ + wmcodec_write(LOUTVOL, IPOD_PCM_LEVEL); + wmcodec_write(ROUTVOL, 0x100 | IPOD_PCM_LEVEL); + + /* ACTIVE=1 */ + codec_set_active(1); + + /* 5. Set DACMU = 0 to soft-un-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x0); + +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* We need to enable bit 4 of GPIOL for output for sound on H10 */ + GPIOL_OUTPUT_VAL |= 0x10; +#endif + audiohw_mute(0); + } else { +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* We need to disable bit 4 of GPIOL to disable sound on H10 */ + GPIOL_OUTPUT_VAL &= ~0x10; +#endif + audiohw_mute(1); + } +} + +int audiohw_set_master_vol(int vol_l, int vol_r) +{ + /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ + /* 1111111 == +6dB */ + /* 1111001 == 0dB */ + /* 0110000 == -73dB */ + /* 0101111 == mute (0x2f) */ + + wmcodec_write(LOUTVOL, VOLUME_ZC_WAIT | vol_l); + wmcodec_write(ROUTVOL, VOLUME_ZC_WAIT | vol_r); + + return 0; +} + +int audiohw_set_mixer_vol(int channel1, int channel2) +{ + (void)channel1; + (void)channel2; + + return 0; +} + +void audiohw_set_bass(int value) +{ + (void)value; +} + +void audiohw_set_treble(int value) +{ + (void)value; +} + +/* Nice shutdown of WM8731 codec */ +void audiohw_close(void) +{ + /* set DACMU=1 DEEMPH=0 */ + wmcodec_write(DACCTRL, 0x8); + + /* ACTIVE=0 */ + codec_set_active(0x0); + + /* line in mute left & right*/ + wmcodec_write(LINVOL, 0x100 | 0x80); + + /* set DACSEL=0, MUTEMIC=1 */ + wmcodec_write(0x4, 0x2); + + /* set POWEROFF=0 OUTPD=0 DACPD=1 */ + wmcodec_write(PWRMGMT, 0x6f); + + /* set POWEROFF=1 OUTPD=1 DACPD=1 */ + wmcodec_write(PWRMGMT, 0xff); +} + +/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ +void audiohw_set_nsorder(int order) +{ + (void)order; +} + +void audiohw_set_sample_rate(int sampling_control) +{ + codec_set_active(0x0); + wmcodec_write(SAMPCTRL, sampling_control); + codec_set_active(0x1); +} + +void audiohw_enable_recording(bool source_mic) +{ + static int line_level = 0x17; + static int mic_boost = true; + codec_set_active(0x0); + + /* set BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 + * LRP=0 IWL=00(16 bit) FORMAT=10(I2S format) */ + wmcodec_write(AINTFCE, 0x42); + + wmcodec_write(LOUTVOL, 0x0); /* headphone mute left */ + wmcodec_write(ROUTVOL, 0x0); /* headphone mute right */ + + + if(source_mic){ + wmcodec_write(LINVOL, 0x80); /* line in mute left */ + wmcodec_write(RINVOL, 0x80); /* line in mute right */ + + + if (mic_boost) { + wmcodec_write(AAPCTRL, 0x5); /* INSEL=mic, MIC_BOOST=enable */ + } else { + wmcodec_write(AAPCTRL, 0x4); /* INSEL=mic */ + } + } else { + if (line_level == 0) { + wmcodec_write(LINVOL, 0x80); + wmcodec_write(RINVOL, 0x80); + } else { + wmcodec_write(LINVOL, line_level); + wmcodec_write(RINVOL, line_level); + } + wmcodec_write(AAPCTRL, 0xa); /* BY PASS, mute mic, INSEL=line in */ + } + + /* disable ADC high pass filter, mute dac */ + wmcodec_write(DACCTRL, 0x9); + + /* power on (PWR_OFF=0) */ + if(source_mic){ + /* CLKOUTPD OSCPD OUTPD DACPD LINEINPD */ + wmcodec_write(PWRMGMT, 0x79); + } else { + wmcodec_write(PWRMGMT, 0x7a); /* MICPD */ + } + + codec_set_active(0x1); +} + +void audiohw_disable_recording(void) +{ + /* set DACMU=1 DEEMPH=0 */ + wmcodec_write(DACCTRL, 0x8); + + /* ACTIVE=0 */ + codec_set_active(0x0); + + /* line in mute left & right*/ + wmcodec_write(LINVOL, 0x80); + wmcodec_write(RINVOL, 0x80); + + /* set DACSEL=0, MUTEMIC=1 */ + wmcodec_write(AAPCTRL, 0x2); + + /* set POWEROFF=0 OUTPD=0 DACPD=1 */ + wmcodec_write(PWRMGMT, 0x6f); + + /* set POWEROFF=1 OUTPD=1 DACPD=1 */ + wmcodec_write(PWRMGMT, 0xff); +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_monitor(int enable) +{ + (void)enable; +} diff --git a/firmware/drivers/audio/wm8758.c b/firmware/drivers/audio/wm8758.c new file mode 100644 index 0000000000..b52bac2f21 --- /dev/null +++ b/firmware/drivers/audio/wm8758.c @@ -0,0 +1,299 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for WM8758 audio codec - based on datasheet for WM8983 + * + * Based on code from the ipodlinux project - http://ipodlinux.org/ + * Adapted for Rockbox in December 2005 + * + * Original file: linux/arch/armnommu/mach-ipod/audio.c + * + * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "debug.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" + +#include "wmcodec.h" +#include "wm8758.h" +#include "i2s.h" + +/* convert tenth of dB volume (-57..6) to master volume register value */ +int tenthdb2master(int db) +{ + /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */ + /* 0111111 == +6dB (0x3f) = 63) */ + /* 0111001 == 0dB (0x39) = 57) */ + /* 0000001 == -56dB (0x01) = */ + /* 0000000 == -57dB (0x00) */ + + /* 1000000 == Mute (0x40) */ + + if (db < VOLUME_MIN) { + return 0x40; + } else { + return((db/10)+57); + } +} + +/* convert tenth of dB volume (-780..0) to mixer volume register value */ +int tenthdb2mixer(int db) +{ + if (db < -660) /* 1.5 dB steps */ + return (2640 - db) / 15; + else if (db < -600) /* 0.75 dB steps */ + return (990 - db) * 2 / 15; + else if (db < -460) /* 0.5 dB steps */ + return (460 - db) / 5; + else /* 0.25 dB steps */ + return -db * 2 / 5; +} + +void audiohw_reset(void); + +#define IPOD_PCM_LEVEL 0x65 /* -6dB */ + +//#define BASSCTRL 0x +//#define TREBCTRL 0x0b + +/* Silently enable / disable audio output */ +void audiohw_enable_output(bool enable) +{ + if (enable) + { + /* reset the I2S controller into known state */ + i2s_reset(); + + /* TODO: Review the power-up sequence to prevent pops */ + + wmcodec_write(RESET, 0x1ff); /*Reset*/ + + wmcodec_write(PWRMGMT1, 0x2b); + wmcodec_write(PWRMGMT2, 0x180); + wmcodec_write(PWRMGMT3, 0x6f); + + wmcodec_write(AINTFCE, 0x10); + wmcodec_write(CLKCTRL, 0x49); + + wmcodec_write(OUTCTRL, 1); + + /* The iPod can handle multiple frequencies, but fix at 44.1KHz + for now */ + audiohw_set_sample_rate(WM8758_44100HZ); + + wmcodec_write(LOUTMIX,0x1); /* Enable mixer */ + wmcodec_write(ROUTMIX,0x1); /* Enable mixer */ + audiohw_mute(0); + } else { + audiohw_mute(1); + } +} + +int audiohw_set_master_vol(int vol_l, int vol_r) +{ + /* OUT1 */ + wmcodec_write(LOUT1VOL, 0x080 | vol_l); + wmcodec_write(ROUT1VOL, 0x180 | vol_r); + + return 0; +} + +int audiohw_set_lineout_vol(int vol_l, int vol_r) +{ + /* OUT2 */ + wmcodec_write(LOUT2VOL, vol_l); + wmcodec_write(ROUT2VOL, 0x100 | vol_r); + + return 0; +} + +int audiohw_set_mixer_vol(int channel1, int channel2) +{ + (void)channel1; + (void)channel2; + + return 0; +} + +/* We are using Linear bass control */ +void audiohw_set_bass(int value) +{ + (void)value; +} + +void audiohw_set_treble(int value) +{ + (void)value; +} + +int audiohw_mute(int mute) +{ + if (mute) + { + /* Set DACMU = 1 to soft-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x40); + } else { + /* Set DACMU = 0 to soft-un-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x0); + } + + return 0; +} + +/* Nice shutdown of WM8758 codec */ +void audiohw_close(void) +{ + audiohw_mute(1); + + wmcodec_write(PWRMGMT3, 0x0); + + wmcodec_write(PWRMGMT1, 0x0); + + wmcodec_write(PWRMGMT2, 0x40); +} + +/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ +void audiohw_set_nsorder(int order) +{ + (void)order; +} + +/* Note: Disable output before calling this function */ +void audiohw_set_sample_rate(int sampling_control) +{ + /**** We force 44.1KHz for now. ****/ + (void)sampling_control; + + /* set clock div */ + wmcodec_write(CLKCTRL, 1 | (0 << 2) | (2 << 5)); + + /* setup PLL for MHZ=11.2896 */ + wmcodec_write(PLLN, (1 << 4) | 0x7); + wmcodec_write(PLLK1, 0x21); + wmcodec_write(PLLK2, 0x161); + wmcodec_write(PLLK3, 0x26); + + /* set clock div */ + wmcodec_write(CLKCTRL, 1 | (1 << 2) | (2 << 5) | (1 << 8)); + + /* set srate */ + wmcodec_write(SRATECTRL, (0 << 1)); +} + +void audiohw_enable_recording(bool source_mic) +{ + (void)source_mic; /* We only have a line-in (I think) */ + + /* reset the I2S controller into known state */ + i2s_reset(); + + wmcodec_write(RESET, 0x1ff); /*Reset*/ + + wmcodec_write(PWRMGMT1, 0x2b); + wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */ + wmcodec_write(PWRMGMT3, 0x6f); + + wmcodec_write(AINTFCE, 0x10); + wmcodec_write(CLKCTRL, 0x49); + + wmcodec_write(OUTCTRL, 1); + + /* The iPod can handle multiple frequencies, but fix at 44.1KHz + for now */ + audiohw_set_sample_rate(WM8758_44100HZ); + + wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */ + + /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */ + /* 000 = disabled + 001 = -12dB + 010 = -9dB + 011 = -6dB + 100 = -3dB + 101 = 0dB + 110 = 3dB + 111 = 6dB + */ + wmcodec_write(LADCBOOST,0x50); + wmcodec_write(RADCBOOST,0x50); + + /* Set L/R input PGA Volume to 0db */ + // wm8758_write(LINPGAVOL,0x3f); + // wm8758_write(RINPGAVOL,0x13f); + + /* Enable monitoring */ + wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/ + wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/ + + audiohw_mute(0); +} + +void audiohw_disable_recording(void) { + audiohw_mute(1); + + wmcodec_write(PWRMGMT3, 0x0); + + wmcodec_write(PWRMGMT1, 0x0); + + wmcodec_write(PWRMGMT2, 0x40); +} + +void audiohw_set_recvol(int left, int right, int type) { + + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_monitor(int enable) { + + (void)enable; +} + +void audiohw_set_equalizer_band(int band, int freq, int bw, int gain) +{ + unsigned int eq = 0; + + /* Band 1..3 are peak filters */ + if (band >= 1 && band <= 3) { + eq |= (bw << 8); + } + + eq |= (freq << 5); + eq |= 12 - gain; + + if (band == 0) { + wmcodec_write(EQ1, eq | 0x100); /* Always apply EQ to the DAC path */ + } else if (band == 1) { + wmcodec_write(EQ2, eq); + } else if (band == 2) { + wmcodec_write(EQ3, eq); + } else if (band == 3) { + wmcodec_write(EQ4, eq); + } else if (band == 4) { + wmcodec_write(EQ5, eq); + } +} diff --git a/firmware/drivers/audio/wm8975.c b/firmware/drivers/audio/wm8975.c new file mode 100644 index 0000000000..9052236131 --- /dev/null +++ b/firmware/drivers/audio/wm8975.c @@ -0,0 +1,318 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for WM8975 audio codec + * + * Based on code from the ipodlinux project - http://ipodlinux.org/ + * Adapted for Rockbox in December 2005 + * + * Original file: linux/arch/armnommu/mach-ipod/audio.c + * + * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "debug.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" + +#include "wmcodec.h" +#include "wm8975.h" +#include "i2s.h" + +/* use zero crossing to reduce clicks during volume changes */ +#define VOLUME_ZC_WAIT (1<<7) + + + +/* convert tenth of dB volume (-730..60) to master volume register value */ +int tenthdb2master(int db) +{ + /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ + /* 1111111 == +6dB (0x7f) */ + /* 1111001 == 0dB (0x79) */ + /* 0110000 == -73dB (0x30 */ + /* 0101111..0000000 == mute (0x2f) */ + + if (db < VOLUME_MIN) { + return 0x0; + } else { + return((db/10)+73+0x30); + } +} + +/* convert tenth of dB volume (-780..0) to mixer volume register value */ +int tenthdb2mixer(int db) +{ + (void)db; + return 0; +} + + +void audiohw_reset(void); + +#define IPOD_PCM_LEVEL 0x65 /* -6dB */ + + +/* Silently enable / disable audio output */ +void audiohw_enable_output(bool enable) +{ + if (enable) + { + /* reset the I2S controller into known state */ + i2s_reset(); + + /* + * 1. Switch on power supplies. + * By default the WM8750L is in Standby Mode, the DAC is + * digitally muted and the Audio Interface, Line outputs + * and Headphone outputs are all OFF (DACMU = 1 Power + * Management registers 1 and 2 are all zeros). + */ + wmcodec_write(RESET, 0x1ff); /*Reset*/ + wmcodec_write(RESET, 0x0); + + /* 2. Enable Vmid and VREF. */ + wmcodec_write(PWRMGMT1, 0xc0); /*Pwr Mgmt(1)*/ + + /* From app notes: allow Vref to stabilize to reduce clicks */ + sleep(HZ/4); + + /* 3. Enable DACs as required. */ + wmcodec_write(PWRMGMT2, 0x180); /*Pwr Mgmt(2)*/ + + /* 4. Enable line and / or headphone output buffers as required. */ + wmcodec_write(PWRMGMT2, 0x1f8); /*Pwr Mgmt(2)*/ + + /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ + /* IWL=00(16 bit) FORMAT=10(I2S format) */ + wmcodec_write(AINTFCE, 0x42); + + /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ + audiohw_set_sample_rate(WM8975_44100HZ); + + /* set the volume to -6dB */ + wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | IPOD_PCM_LEVEL); + wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | IPOD_PCM_LEVEL); + + wmcodec_write(LOUTMIX1, 0x150); /* Left out Mix(def) */ + wmcodec_write(LOUTMIX2, 0x50); + + wmcodec_write(ROUTMIX1, 0x50); /* Right out Mix(def) */ + wmcodec_write(ROUTMIX2, 0x150); + + wmcodec_write(MOUTMIX1, 0x0); /* Mono out Mix */ + wmcodec_write(MOUTMIX2, 0x0); + + audiohw_mute(0); + } else { + audiohw_mute(1); + } +} + + + +int audiohw_set_master_vol(int vol_l, int vol_r) +{ + /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ + /* 1111111 == +6dB */ + /* 1111001 == 0dB */ + /* 0110000 == -73dB */ + /* 0101111 == mute (0x2f) */ + + /* OUT1 */ + wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | vol_l); + wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); + + return 0; +} + +int audiohw_set_lineout_vol(int vol_l, int vol_r) +{ + /* OUT2 */ + wmcodec_write(LOUT2VOL, VOLUME_ZC_WAIT | vol_l); + wmcodec_write(ROUT2VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); + + return 0; +} + +int audiohw_set_mixer_vol(int channel1, int channel2) +{ + (void)channel1; + (void)channel2; + + return 0; +} + +void audiohw_set_bass(int value) +{ + const int regvalues[] = { + 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 + }; + + if ((value >= -6) && (value <= 9)) { + /* We use linear bass control with 200 Hz cutoff */ + wmcodec_write(BASSCTRL, regvalues[value + 6] | 0x40); + } +} + +void audiohw_set_treble(int value) +{ + const int regvalues[] = { + 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 + }; + + if ((value >= -6) && (value <= 9)) { + /* We use linear treble control with 4 kHz cutoff */ + wmcodec_write(TREBCTRL, regvalues[value + 6] | 0x40); + } +} + +int audiohw_mute(int mute) +{ + if (mute) + { + /* Set DACMU = 1 to soft-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x8); + } else { + /* Set DACMU = 0 to soft-un-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x0); + } + + return 0; +} + +/* Nice shutdown of WM8975 codec */ +void audiohw_close(void) +{ + /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ + wmcodec_write(DACCTRL, 0x8); + + /* 2. Disable all output buffers. */ + wmcodec_write(PWRMGMT2, 0x0); /*Pwr Mgmt(2)*/ + + /* 3. Switch off the power supplies. */ + wmcodec_write(PWRMGMT1, 0x0); /*Pwr Mgmt(1)*/ +} + +/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ +void audiohw_set_nsorder(int order) +{ + (void)order; +} + +/* Note: Disable output before calling this function */ +void audiohw_set_sample_rate(int sampling_control) { + + wmcodec_write(0x08, sampling_control); + +} + +void audiohw_enable_recording(bool source_mic) +{ + (void)source_mic; + + /* reset the I2S controller into known state */ + i2s_reset(); + + /* + * 1. Switch on power supplies. + * By default the WM8750L is in Standby Mode, the DAC is + * digitally muted and the Audio Interface, Line outputs + * and Headphone outputs are all OFF (DACMU = 1 Power + * Management registers 1 and 2 are all zeros). + */ + wmcodec_write(0x0f, 0x1ff); + wmcodec_write(0x0f, 0x000); + + /* 2. Enable Vmid and VREF. */ + wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/ + + /* 3. Enable ADCs as required. */ + wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/ + wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/ + + /* 4. Enable line and / or headphone output buffers as required. */ + wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/ + + /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ + /* IWL=00(16 bit) FORMAT=10(I2S format) */ + wmcodec_write(0x07, 0x42); + + /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ + audiohw_set_sample_rate(WM8975_44100HZ); + + /* unmute inputs */ + wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */ + wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */ + + wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */ + wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */ + + if (source_mic) { + /* VSEL=10(def) DATSEL=10 (use right ADC only) */ + wmcodec_write(0x17, 0xc9); /* Additional control(1) */ + + /* VROI=1 (sets output resistance to 40kohms) */ + wmcodec_write(0x1b, 0x40); /* Additional control(3) */ + + /* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */ + wmcodec_write(0x20, 0x60); /* ADCL signal path */ + wmcodec_write(0x21, 0x60); /* ADCR signal path */ + } else { + /* VSEL=10(def) DATSEL=00 (left->left, right->right) */ + wmcodec_write(0x17, 0xc1); /* Additional control(1) */ + + /* VROI=1 (sets output resistance to 40kohms) */ + wmcodec_write(0x1b, 0x40); /* Additional control(3) */ + + /* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */ + wmcodec_write(0x20, 0x00); /* ADCL signal path */ + /* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */ + wmcodec_write(0x21, 0x00); /* ADCR signal path */ + } +} + +void audiohw_disable_recording(void) { + /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ + wmcodec_write(0x05, 0x8); + + /* 2. Disable all output buffers. */ + wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/ + + /* 3. Switch off the power supplies. */ + wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/ +} + +void audiohw_set_recvol(int left, int right, int type) { + + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_monitor(int enable) { + + (void)enable; +} diff --git a/firmware/drivers/tlv320.c b/firmware/drivers/tlv320.c deleted file mode 100644 index 3e27d22817..0000000000 --- a/firmware/drivers/tlv320.c +++ /dev/null @@ -1,305 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 by Christian Gmeiner - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "power.h" -#include "logf.h" -#include "system.h" -#include "sprintf.h" -#include "button.h" -#include "string.h" -#include "file.h" -#include "buffer.h" -#include "audio.h" - -#include "i2c-coldfire.h" -#include "tlv320.h" - -/* convert tenth of dB volume (-840..0) to master volume register value */ -int tenthdb2master(int db) -{ - /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ - /* 1111111 == +6dB (0x7f) */ - /* 1111001 == 0dB (0x79) */ - /* 0110000 == -73dB (0x30 */ - /* 0101111 == mute (0x2f) */ - - if (db < VOLUME_MIN) { - return 0x2f; - } else { - return((db/10)+73+0x30); - } -} - -/* local functions and definations */ -#define TLV320_ADDR 0x34 - -struct tlv320_info -{ - int vol_l; - int vol_r; -} tlv320; - -/* Shadow registers */ -unsigned tlv320_regs[0xf]; - -void tlv320_write_reg(unsigned reg, unsigned value) -{ - unsigned char data[2]; - - /* The register address is the high 7 bits and the data the low 9 bits */ - data[0] = (reg << 1) | ((value >> 8) & 1); - data[1] = value; - - if (i2c_write(I2C_IFACE_0, TLV320_ADDR, data, 2) != 2) - { - logf("tlv320 error reg=0x%x", reg); - return; - } - - tlv320_regs[reg] = value; -} - -/* public functions */ - -/** - * Init our tlv with default values - */ -void audiohw_init(void) -{ - memset(tlv320_regs, 0, sizeof(tlv320_regs)); - - /* Initialize all registers */ - - /* All ON except OUT, ADC, MIC and LINE */ - tlv320_write_reg(REG_PC, PC_OUT | PC_ADC | PC_MIC | PC_LINE); - audiohw_set_recvol(0, 0, AUDIO_GAIN_MIC); - audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN); - audiohw_mute(true); - tlv320_write_reg(REG_AAP, AAP_DAC | AAP_MICM); - tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ - tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); - tlv320_write_reg(REG_DIA, DIA_ACT); - audiohw_set_frequency(-1); /* default */ -} - -/** - * Switch outputs ON - */ -void audiohw_postinit(void) -{ - /* All ON except ADC, MIC and LINE */ - sleep(HZ); - tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); - sleep(HZ/4); - audiohw_mute(false); -} - -/** - * Resets tlv320 to default values - */ -void audiohw_reset(void) -{ - tlv320_write_reg(REG_RR, RR_RESET); -} - -/** - * Sets internal sample rate for DAC and ADC relative to MCLK - * Selection for frequency: - * Fs: tlv: with: - * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 - * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 - * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) - * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 - */ -void audiohw_set_frequency(unsigned fsel) -{ - /* All rates available for 11.2896MHz besides 8.021 */ - unsigned char values_src[3] = - { - /* Fs: */ - (0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */ - (0x8 << 2), /* 44100 */ - (0xf << 2), /* 88200 */ - }; - - unsigned value_dap, value_pc; - - if (fsel >= ARRAYLEN(values_src)) - fsel = 1; - - /* Temporarily turn off the DAC and ADC before switching sample - rates or they don't choose their filters correctly */ - value_dap = tlv320_regs[REG_DAP]; - value_pc = tlv320_regs[REG_PC]; - - tlv320_write_reg(REG_DAP, value_dap | DAP_DACM); - tlv320_write_reg(REG_PC, value_pc | PC_DAC | PC_ADC); - tlv320_write_reg(REG_SRC, values_src[fsel]); - tlv320_write_reg(REG_PC, value_pc | PC_DAC); - tlv320_write_reg(REG_PC, value_pc); - tlv320_write_reg(REG_DAP, value_dap); -} - -/** - * Sets left and right headphone volume - * - * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB - */ -void audiohw_set_headphone_vol(int vol_l, int vol_r) -{ - unsigned value_dap = tlv320_regs[REG_DAP]; - unsigned value_dap_last = value_dap; - unsigned value_l = LHV_LHV(vol_l); - unsigned value_r = RHV_RHV(vol_r); - - /* keep track of current setting */ - tlv320.vol_l = vol_l; - tlv320.vol_r = vol_r; - - if (value_l > HEADPHONE_MUTE || value_r > HEADPHONE_MUTE) - value_dap &= ~DAP_DACM; - else - value_dap |= DAP_DACM; - - /* update */ - tlv320_write_reg(REG_LHV, LHV_LZC | value_l); - tlv320_write_reg(REG_RHV, RHV_RZC | value_r); - if (value_dap != value_dap_last) - tlv320_write_reg(REG_DAP, value_dap); -} - -/** - * Set recording volume - * - * Line in : 0 .. 31 => Volume -34.5 .. +12 dB - * Mic (left): 0 .. 1 => Volume +0, +20 dB - * - */ -void audiohw_set_recvol(int left, int right, int type) -{ - if (type == AUDIO_GAIN_MIC) - { - unsigned value_aap = tlv320_regs[REG_AAP]; - - if (left) - value_aap |= AAP_MICB; /* Enable mic boost (20dB) */ - else - value_aap &= ~AAP_MICB; - - tlv320_write_reg(REG_AAP, value_aap); - } - else if (type == AUDIO_GAIN_LINEIN) - { - tlv320_write_reg(REG_LLIV, LLIV_LIV(left)); - tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); - } -} - -/** - * Mute (mute=true) or enable sound (mute=false) - * - */ -void audiohw_mute(bool mute) -{ - unsigned value_dap = tlv320_regs[REG_DAP]; - unsigned value_l, value_r; - - if (mute) - { - value_l = LHV_LHV(HEADPHONE_MUTE); - value_r = RHV_RHV(HEADPHONE_MUTE); - value_dap |= DAP_DACM; - } - else - { - value_l = LHV_LHV(tlv320.vol_l); - value_r = RHV_RHV(tlv320.vol_r); - if (value_l > HEADPHONE_MUTE || value_r > HEADPHONE_MUTE) - value_dap &= ~DAP_DACM; - } - - tlv320_write_reg(REG_LHV, LHV_LZC | value_l); - tlv320_write_reg(REG_RHV, RHV_RZC | value_r); - tlv320_write_reg(REG_DAP, value_dap); -} - -/* Nice shutdown of TLV320 codec */ -void audiohw_close(void) -{ - audiohw_mute(true); - sleep(HZ/8); - - tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | - PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ -} - -void audiohw_enable_recording(bool source_mic) -{ - unsigned value_aap, value_pc; - - if (source_mic) - { - /* select MIC and enable mic boost (20 dB) */ - value_aap = AAP_DAC | AAP_INSEL | AAP_MICB; - value_pc = PC_LINE; /* power down LINE */ - } - else - { - value_aap = AAP_DAC | AAP_MICM; - value_pc = PC_MIC; /* power down MIC */ - } - - tlv320_write_reg(REG_PC, value_pc); - tlv320_write_reg(REG_AAP, value_aap); -} - -void audiohw_disable_recording(void) -{ - unsigned value_pc = tlv320_regs[REG_PC]; - unsigned value_aap = tlv320_regs[REG_AAP]; - - value_aap |= AAP_MICM; /* mute MIC */ - tlv320_write_reg(REG_PC, value_aap); - - value_pc |= PC_ADC | PC_MIC | PC_LINE; /* ADC, MIC and LINE off */ - tlv320_write_reg(REG_PC, value_pc); -} - -void audiohw_set_monitor(bool enable) -{ - unsigned value_aap, value_pc; - - if (enable) - { - /* Keep DAC on to allow mixing of voice with analog audio */ - value_aap = AAP_DAC | AAP_BYPASS | AAP_MICM; - value_pc = PC_ADC | PC_MIC; /* ADC and MIC off */ - } - else - { - value_aap = AAP_DAC | AAP_MICM; - value_pc = PC_ADC | PC_MIC | PC_LINE; /* ADC, MIC and LINE off */ - } - - tlv320_write_reg(REG_AAP, value_aap); - tlv320_write_reg(REG_PC, value_pc); -} diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c deleted file mode 100644 index 6984427fc9..0000000000 --- a/firmware/drivers/uda1380.c +++ /dev/null @@ -1,460 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 by Andy Young - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "power.h" -#include "debug.h" -#include "system.h" -#include "sprintf.h" -#include "button.h" -#include "string.h" -#include "file.h" -#include "buffer.h" -#include "audio.h" -#include "logf.h" - -#include "i2c-coldfire.h" -#include "uda1380.h" -#include "pcf50606.h" - -/* convert tenth of dB volume (-840..0) to master volume register value */ -int tenthdb2master(int db) -{ - if (db < -720) /* 1.5 dB steps */ - return (2940 - db) / 15; - else if (db < -660) /* 0.75 dB steps */ - return (1110 - db) * 2 / 15; - else if (db < -520) /* 0.5 dB steps */ - return (520 - db) / 5; - else /* 0.25 dB steps */ - return -db * 2 / 5; -} - -/* convert tenth of dB volume (-780..0) to mixer volume register value */ -int tenthdb2mixer(int db) -{ - if (db < -660) /* 1.5 dB steps */ - return (2640 - db) / 15; - else if (db < -600) /* 0.75 dB steps */ - return (990 - db) * 2 / 15; - else if (db < -460) /* 0.5 dB steps */ - return (460 - db) / 5; - else /* 0.25 dB steps */ - return -db * 2 / 5; -} - -/* ------------------------------------------------- */ -/* Local functions and variables */ -/* ------------------------------------------------- */ - -int uda1380_write_reg(unsigned char reg, unsigned short value); -unsigned short uda1380_regs[0x30]; -short recgain_mic; -short recgain_line; - -/* Definition of a playback configuration to start with */ - -#define NUM_DEFAULT_REGS 13 -unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = -{ - REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK | - SYSCLK_256FS | WSPLL_25_50, - REG_I2S, I2S_IFMT_IIS, - REG_PWR, PON_PLL | PON_BIAS, - /* PON_HP & PON_DAC is enabled later */ - REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), - /* 00=max, 3f=mute */ - REG_MASTER_VOL, MASTER_VOL_LEFT(0x20) | MASTER_VOL_RIGHT(0x20), - /* 00=max, ff=mute */ - REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), - /* 00=max, ff=mute */ - REG_EQ, EQ_MODE_MAX, - /* Bass and treble = 0 dB */ - REG_MUTE, MUTE_MASTER | MUTE_CH2, - /* Mute everything to start with */ - REG_MIX_CTL, MIX_CTL_MIX, - /* Enable mixer */ - REG_DEC_VOL, 0, - REG_PGA, MUTE_ADC, - REG_ADC, SKIP_DCFIL, - REG_AGC, 0 -}; - - - -/* Returns 0 if register was written or -1 if write failed */ -int uda1380_write_reg(unsigned char reg, unsigned short value) -{ - unsigned char data[3]; - - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0xff; - - if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 3) != 3) - { - DEBUGF("uda1380 error reg=0x%x", reg); - return -1; - } - - uda1380_regs[reg] = value; - - return 0; -} - -/** - * Sets left and right master volume (0(max) to 252(muted)) - */ -int audiohw_set_master_vol(int vol_l, int vol_r) -{ - return uda1380_write_reg(REG_MASTER_VOL, - MASTER_VOL_LEFT(vol_l) | MASTER_VOL_RIGHT(vol_r)); -} - -/** - * Sets mixer volume for both channels (0(max) to 228(muted)) - */ -int audiohw_set_mixer_vol(int channel1, int channel2) -{ - return uda1380_write_reg(REG_MIX_VOL, - MIX_VOL_CH_1(channel1) | MIX_VOL_CH_2(channel2)); -} - -/** - * Sets the bass value (0-12) - */ -void audiohw_set_bass(int value) -{ - uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~BASS_MASK) - | BASSL(value) | BASSR(value)); -} - -/** - * Sets the treble value (0-3) - */ -void audiohw_set_treble(int value) -{ - uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~TREBLE_MASK) - | TREBLEL(value) | TREBLER(value)); -} - -/** - * Mute (mute=1) or enable sound (mute=0) - * - */ -int audiohw_mute(int mute) -{ - unsigned int value = uda1380_regs[REG_MUTE]; - - if (mute) - value = value | MUTE_MASTER; - else - value = value & ~MUTE_MASTER; - - return uda1380_write_reg(REG_MUTE, value); -} - -/* Returns 0 if successful or -1 if some register failed */ -int audiohw_set_regs(void) -{ - int i; - memset(uda1380_regs, 0, sizeof(uda1380_regs)); - - /* Initialize all registers */ - for (i=0; i= ARRAYLEN(values_reg)) - fsel = 2; - - ent = values_reg[fsel]; - - /* Set WSPLL input frequency range or SYSCLK divider */ - uda1380_regs[REG_0] &= ~0xf; - uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]); - - /* Choose 3rd order or 5th order noise shaper */ - uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS; - uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]); -} - -/* Initialize UDA1380 codec with default register values (uda1380_defaults) */ -int audiohw_init(void) -{ - recgain_mic = 0; - recgain_line = 0; - - audiohw_reset(); - - if (audiohw_set_regs() == -1) - return -1; - - return 0; -} - -void audiohw_postinit(void) -{ - /* Sleep a while so the power can stabilize (especially a long - delay is needed for the line out connector). */ - sleep(HZ); - /* Power on FSDAC and HP amp. */ - audiohw_enable_output(true); - - /* UDA1380: Unmute the master channel - (DAC should be at zero point now). */ - audiohw_mute(false); -} - -/* Nice shutdown of UDA1380 codec */ -void audiohw_close(void) -{ - /* First enable mute and sleep a while */ - uda1380_write_reg(REG_MUTE, MUTE_MASTER); - sleep(HZ/8); - - /* Then power off the rest of the chip */ - uda1380_write_reg(REG_PWR, 0); - uda1380_write_reg(REG_0, 0); /* Disable codec */ -} - -/** - * Calling this function enables the UDA1380 to send - * sound samples over the I2S bus, which is connected - * to the processor's IIS1 interface. - * - * source_mic: true=record from microphone, false=record from line-in (or radio) - */ -void audiohw_enable_recording(bool source_mic) -{ - uda1380_regs[REG_0] &= ~(ADC_CLK | DAC_CLK); - uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); - - if (source_mic) - { - /* VGA_GAIN: 0=0 dB, F=30dB */ - /* Output of left ADC is fed into right bitstream */ - uda1380_regs[REG_PWR] &= ~(PON_PGAR | PON_ADCR); - uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); - uda1380_regs[REG_ADC] &= ~SKIP_DCFIL; - uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) - | SEL_LNA | SEL_MIC | EN_DCFIL); - uda1380_write_reg(REG_PGA, 0); - } - else - { - /* PGA_GAIN: 0=0 dB, F=24dB */ - uda1380_regs[REG_PWR] &= ~PON_LNA; - uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL - | PON_PGAR | PON_ADCR); - uda1380_write_reg(REG_ADC, EN_DCFIL); - uda1380_write_reg(REG_PGA, uda1380_regs[REG_PGA] & PGA_GAIN_MASK); - } - - sleep(HZ/8); - - uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); - uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); -} - -/** - * Stop sending samples on the I2S bus - */ -void audiohw_disable_recording(void) -{ - uda1380_write_reg(REG_PGA, MUTE_ADC); - sleep(HZ/8); - - uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); - - uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | - PON_PGAL | PON_PGAR); - uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR]); - - uda1380_regs[REG_0] &= ~EN_ADC; - uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ADC_CLK | DAC_CLK); - - uda1380_write_reg(REG_ADC, SKIP_DCFIL); -} - -/** - * Set recording gain and volume - * - * type: params: ranges: - * AUDIO_GAIN_MIC: left -128 .. 108 -> -64 .. 54 dB gain - * AUDIO_GAIN_LINEIN left & right -128 .. 96 -> -64 .. 48 dB gain - * - * Note: - For all types the value 0 gives 0 dB gain. - * - order of setting both values determines if the small glitch will - be a peak or a dip. The small glitch is caused by the time between - setting the two gains - */ -void audiohw_set_recvol(int left, int right, int type) -{ - int left_ag, right_ag; - - switch (type) - { - case AUDIO_GAIN_MIC: - left_ag = MIN(MAX(0, left / 4), 15); - left -= left_ag * 4; - - if(left < recgain_mic) - { - uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) - | DEC_VOLR(left)); - uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] - & ~VGA_GAIN_MASK) - | VGA_GAIN(left_ag)); - } - else - { - uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] - & ~VGA_GAIN_MASK) - | VGA_GAIN(left_ag)); - uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) - | DEC_VOLR(left)); - } - recgain_mic = left; - logf("Mic: %dA/%dD", left_ag, left); - break; - - case AUDIO_GAIN_LINEIN: - left_ag = MIN(MAX(0, left / 6), 8); - left -= left_ag * 6; - right_ag = MIN(MAX(0, right / 6), 8); - right -= right_ag * 6; - - if(left < recgain_line) - { - /* for this order we can combine both registers, - making the glitch even smaller */ - unsigned char data[5]; - unsigned short value_dec; - unsigned short value_pga; - value_dec = DEC_VOLL(left) | DEC_VOLR(right); - value_pga = (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) - | PGA_GAINL(left_ag) | PGA_GAINR(right_ag); - - data[0] = REG_DEC_VOL; - data[1] = value_dec >> 8; - data[2] = value_dec & 0xff; - data[3] = value_pga >> 8; - data[4] = value_pga & 0xff; - - if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 5) != 5) - { - DEBUGF("uda1380 error reg=combi rec gain"); - } - else - { - uda1380_regs[REG_DEC_VOL] = value_dec; - uda1380_regs[REG_PGA] = value_pga; - } - } - else - { - uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] - & ~PGA_GAIN_MASK) - | PGA_GAINL(left_ag) - | PGA_GAINR(right_ag)); - uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) - | DEC_VOLR(right)); - } - - recgain_line = left; - logf("Line L: %dA/%dD", left_ag, left); - logf("Line R: %dA/%dD", right_ag, right); - break; - } -} - - -/** - * Enable or disable recording monitor (so one can listen to the recording) - * - */ -void audiohw_set_monitor(int enable) -{ - if (enable) /* enable channel 2 */ - uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] & ~MUTE_CH2); - else /* mute channel 2 */ - uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); -} diff --git a/firmware/drivers/wm8731l.c b/firmware/drivers/wm8731l.c deleted file mode 100644 index 62b1b6a81e..0000000000 --- a/firmware/drivers/wm8731l.c +++ /dev/null @@ -1,305 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Driver for WM8731L audio codec - * - * Based on code from the ipodlinux project - http://ipodlinux.org/ - * Adapted for Rockbox in January 2006 - * - * Original file: linux/arch/armnommu/mach-ipod/audio.c - * - * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "power.h" -#include "debug.h" -#include "system.h" -#include "sprintf.h" -#include "button.h" -#include "string.h" -#include "file.h" -#include "buffer.h" -#include "audio.h" - -#include "wmcodec.h" -#include "wm8731l.h" -#include "i2s.h" - -#define IPOD_PCM_LEVEL 0x65 /* -6dB */ - -/* use zero crossing to reduce clicks during volume changes */ -#define VOLUME_ZC_WAIT (1<<7) - -/* convert tenth of dB volume (-730..60) to master volume register value */ -int tenthdb2master(int db) -{ - /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ - /* 1111111 == +6dB (0x7f) */ - /* 1111001 == 0dB (0x79) */ - /* 0110000 == -73dB (0x30 */ - /* 0101111 == mute (0x2f) */ - - if (db < VOLUME_MIN) { - return 0x2f; - } else { - return((db/10)+0x30+73); - } -} - -/* convert tenth of dB volume (-780..0) to mixer volume register value */ -int tenthdb2mixer(int db) -{ - if (db < -660) /* 1.5 dB steps */ - return (2640 - db) / 15; - else if (db < -600) /* 0.75 dB steps */ - return (990 - db) * 2 / 15; - else if (db < -460) /* 0.5 dB steps */ - return (460 - db) / 5; - else /* 0.25 dB steps */ - return -db * 2 / 5; -} - -int audiohw_mute(int mute) -{ - if (mute) - { - /* Set DACMU = 1 to soft-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x8); - } else { - /* Set DACMU = 0 to soft-un-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x0); - } - - return 0; -} - -/** From ipodLinux **/ -static void codec_set_active(int active) -{ - /* set active to 0x0 or 0x1 */ - if (active) { - wmcodec_write(ACTIVECTRL, 0x01); - } else { - wmcodec_write(ACTIVECTRL, 0x00); - } -} - - -/* Silently enable / disable audio output */ -void audiohw_enable_output(bool enable) -{ - if (enable) - { - /* reset the I2S controller into known state */ - i2s_reset(); - - wmcodec_write(RESET, 0x0); /*Reset*/ - - codec_set_active(0x0); - -#ifdef HAVE_WM8721 - /* DACSEL=1 */ - wmcodec_write(0x4, 0x10); -#elif defined HAVE_WM8731 - /* DACSEL=1, BYPASS=1 */ - wmcodec_write(0x4, 0x18); -#endif - - /* set power register to POWEROFF=0 on OUTPD=0, DACPD=0 */ - wmcodec_write(PWRMGMT, 0x67); - - /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ - /* IWL=00(16 bit) FORMAT=10(I2S format) */ - wmcodec_write(AINTFCE, 0x42); - - audiohw_set_sample_rate(WM8731L_44100HZ); - - /* set the volume to -6dB */ - wmcodec_write(LOUTVOL, IPOD_PCM_LEVEL); - wmcodec_write(ROUTVOL, 0x100 | IPOD_PCM_LEVEL); - - /* ACTIVE=1 */ - codec_set_active(1); - - /* 5. Set DACMU = 0 to soft-un-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x0); - -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* We need to enable bit 4 of GPIOL for output for sound on H10 */ - GPIOL_OUTPUT_VAL |= 0x10; -#endif - audiohw_mute(0); - } else { -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* We need to disable bit 4 of GPIOL to disable sound on H10 */ - GPIOL_OUTPUT_VAL &= ~0x10; -#endif - audiohw_mute(1); - } -} - -int audiohw_set_master_vol(int vol_l, int vol_r) -{ - /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ - /* 1111111 == +6dB */ - /* 1111001 == 0dB */ - /* 0110000 == -73dB */ - /* 0101111 == mute (0x2f) */ - - wmcodec_write(LOUTVOL, VOLUME_ZC_WAIT | vol_l); - wmcodec_write(ROUTVOL, VOLUME_ZC_WAIT | vol_r); - - return 0; -} - -int audiohw_set_mixer_vol(int channel1, int channel2) -{ - (void)channel1; - (void)channel2; - - return 0; -} - -void audiohw_set_bass(int value) -{ - (void)value; -} - -void audiohw_set_treble(int value) -{ - (void)value; -} - -/* Nice shutdown of WM8731 codec */ -void audiohw_close(void) -{ - /* set DACMU=1 DEEMPH=0 */ - wmcodec_write(DACCTRL, 0x8); - - /* ACTIVE=0 */ - codec_set_active(0x0); - - /* line in mute left & right*/ - wmcodec_write(LINVOL, 0x100 | 0x80); - - /* set DACSEL=0, MUTEMIC=1 */ - wmcodec_write(0x4, 0x2); - - /* set POWEROFF=0 OUTPD=0 DACPD=1 */ - wmcodec_write(PWRMGMT, 0x6f); - - /* set POWEROFF=1 OUTPD=1 DACPD=1 */ - wmcodec_write(PWRMGMT, 0xff); -} - -/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ -void audiohw_set_nsorder(int order) -{ - (void)order; -} - -void audiohw_set_sample_rate(int sampling_control) -{ - codec_set_active(0x0); - wmcodec_write(SAMPCTRL, sampling_control); - codec_set_active(0x1); -} - -void audiohw_enable_recording(bool source_mic) -{ - static int line_level = 0x17; - static int mic_boost = true; - codec_set_active(0x0); - - /* set BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 - * LRP=0 IWL=00(16 bit) FORMAT=10(I2S format) */ - wmcodec_write(AINTFCE, 0x42); - - wmcodec_write(LOUTVOL, 0x0); /* headphone mute left */ - wmcodec_write(ROUTVOL, 0x0); /* headphone mute right */ - - - if(source_mic){ - wmcodec_write(LINVOL, 0x80); /* line in mute left */ - wmcodec_write(RINVOL, 0x80); /* line in mute right */ - - - if (mic_boost) { - wmcodec_write(AAPCTRL, 0x5); /* INSEL=mic, MIC_BOOST=enable */ - } else { - wmcodec_write(AAPCTRL, 0x4); /* INSEL=mic */ - } - } else { - if (line_level == 0) { - wmcodec_write(LINVOL, 0x80); - wmcodec_write(RINVOL, 0x80); - } else { - wmcodec_write(LINVOL, line_level); - wmcodec_write(RINVOL, line_level); - } - wmcodec_write(AAPCTRL, 0xa); /* BY PASS, mute mic, INSEL=line in */ - } - - /* disable ADC high pass filter, mute dac */ - wmcodec_write(DACCTRL, 0x9); - - /* power on (PWR_OFF=0) */ - if(source_mic){ - /* CLKOUTPD OSCPD OUTPD DACPD LINEINPD */ - wmcodec_write(PWRMGMT, 0x79); - } else { - wmcodec_write(PWRMGMT, 0x7a); /* MICPD */ - } - - codec_set_active(0x1); -} - -void audiohw_disable_recording(void) -{ - /* set DACMU=1 DEEMPH=0 */ - wmcodec_write(DACCTRL, 0x8); - - /* ACTIVE=0 */ - codec_set_active(0x0); - - /* line in mute left & right*/ - wmcodec_write(LINVOL, 0x80); - wmcodec_write(RINVOL, 0x80); - - /* set DACSEL=0, MUTEMIC=1 */ - wmcodec_write(AAPCTRL, 0x2); - - /* set POWEROFF=0 OUTPD=0 DACPD=1 */ - wmcodec_write(PWRMGMT, 0x6f); - - /* set POWEROFF=1 OUTPD=1 DACPD=1 */ - wmcodec_write(PWRMGMT, 0xff); -} - -void audiohw_set_recvol(int left, int right, int type) -{ - (void)left; - (void)right; - (void)type; -} - -void audiohw_set_monitor(int enable) -{ - (void)enable; -} diff --git a/firmware/drivers/wm8758.c b/firmware/drivers/wm8758.c deleted file mode 100644 index b52bac2f21..0000000000 --- a/firmware/drivers/wm8758.c +++ /dev/null @@ -1,299 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Driver for WM8758 audio codec - based on datasheet for WM8983 - * - * Based on code from the ipodlinux project - http://ipodlinux.org/ - * Adapted for Rockbox in December 2005 - * - * Original file: linux/arch/armnommu/mach-ipod/audio.c - * - * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "power.h" -#include "debug.h" -#include "system.h" -#include "sprintf.h" -#include "button.h" -#include "string.h" -#include "file.h" -#include "buffer.h" -#include "audio.h" - -#include "wmcodec.h" -#include "wm8758.h" -#include "i2s.h" - -/* convert tenth of dB volume (-57..6) to master volume register value */ -int tenthdb2master(int db) -{ - /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */ - /* 0111111 == +6dB (0x3f) = 63) */ - /* 0111001 == 0dB (0x39) = 57) */ - /* 0000001 == -56dB (0x01) = */ - /* 0000000 == -57dB (0x00) */ - - /* 1000000 == Mute (0x40) */ - - if (db < VOLUME_MIN) { - return 0x40; - } else { - return((db/10)+57); - } -} - -/* convert tenth of dB volume (-780..0) to mixer volume register value */ -int tenthdb2mixer(int db) -{ - if (db < -660) /* 1.5 dB steps */ - return (2640 - db) / 15; - else if (db < -600) /* 0.75 dB steps */ - return (990 - db) * 2 / 15; - else if (db < -460) /* 0.5 dB steps */ - return (460 - db) / 5; - else /* 0.25 dB steps */ - return -db * 2 / 5; -} - -void audiohw_reset(void); - -#define IPOD_PCM_LEVEL 0x65 /* -6dB */ - -//#define BASSCTRL 0x -//#define TREBCTRL 0x0b - -/* Silently enable / disable audio output */ -void audiohw_enable_output(bool enable) -{ - if (enable) - { - /* reset the I2S controller into known state */ - i2s_reset(); - - /* TODO: Review the power-up sequence to prevent pops */ - - wmcodec_write(RESET, 0x1ff); /*Reset*/ - - wmcodec_write(PWRMGMT1, 0x2b); - wmcodec_write(PWRMGMT2, 0x180); - wmcodec_write(PWRMGMT3, 0x6f); - - wmcodec_write(AINTFCE, 0x10); - wmcodec_write(CLKCTRL, 0x49); - - wmcodec_write(OUTCTRL, 1); - - /* The iPod can handle multiple frequencies, but fix at 44.1KHz - for now */ - audiohw_set_sample_rate(WM8758_44100HZ); - - wmcodec_write(LOUTMIX,0x1); /* Enable mixer */ - wmcodec_write(ROUTMIX,0x1); /* Enable mixer */ - audiohw_mute(0); - } else { - audiohw_mute(1); - } -} - -int audiohw_set_master_vol(int vol_l, int vol_r) -{ - /* OUT1 */ - wmcodec_write(LOUT1VOL, 0x080 | vol_l); - wmcodec_write(ROUT1VOL, 0x180 | vol_r); - - return 0; -} - -int audiohw_set_lineout_vol(int vol_l, int vol_r) -{ - /* OUT2 */ - wmcodec_write(LOUT2VOL, vol_l); - wmcodec_write(ROUT2VOL, 0x100 | vol_r); - - return 0; -} - -int audiohw_set_mixer_vol(int channel1, int channel2) -{ - (void)channel1; - (void)channel2; - - return 0; -} - -/* We are using Linear bass control */ -void audiohw_set_bass(int value) -{ - (void)value; -} - -void audiohw_set_treble(int value) -{ - (void)value; -} - -int audiohw_mute(int mute) -{ - if (mute) - { - /* Set DACMU = 1 to soft-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x40); - } else { - /* Set DACMU = 0 to soft-un-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x0); - } - - return 0; -} - -/* Nice shutdown of WM8758 codec */ -void audiohw_close(void) -{ - audiohw_mute(1); - - wmcodec_write(PWRMGMT3, 0x0); - - wmcodec_write(PWRMGMT1, 0x0); - - wmcodec_write(PWRMGMT2, 0x40); -} - -/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ -void audiohw_set_nsorder(int order) -{ - (void)order; -} - -/* Note: Disable output before calling this function */ -void audiohw_set_sample_rate(int sampling_control) -{ - /**** We force 44.1KHz for now. ****/ - (void)sampling_control; - - /* set clock div */ - wmcodec_write(CLKCTRL, 1 | (0 << 2) | (2 << 5)); - - /* setup PLL for MHZ=11.2896 */ - wmcodec_write(PLLN, (1 << 4) | 0x7); - wmcodec_write(PLLK1, 0x21); - wmcodec_write(PLLK2, 0x161); - wmcodec_write(PLLK3, 0x26); - - /* set clock div */ - wmcodec_write(CLKCTRL, 1 | (1 << 2) | (2 << 5) | (1 << 8)); - - /* set srate */ - wmcodec_write(SRATECTRL, (0 << 1)); -} - -void audiohw_enable_recording(bool source_mic) -{ - (void)source_mic; /* We only have a line-in (I think) */ - - /* reset the I2S controller into known state */ - i2s_reset(); - - wmcodec_write(RESET, 0x1ff); /*Reset*/ - - wmcodec_write(PWRMGMT1, 0x2b); - wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */ - wmcodec_write(PWRMGMT3, 0x6f); - - wmcodec_write(AINTFCE, 0x10); - wmcodec_write(CLKCTRL, 0x49); - - wmcodec_write(OUTCTRL, 1); - - /* The iPod can handle multiple frequencies, but fix at 44.1KHz - for now */ - audiohw_set_sample_rate(WM8758_44100HZ); - - wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */ - - /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */ - /* 000 = disabled - 001 = -12dB - 010 = -9dB - 011 = -6dB - 100 = -3dB - 101 = 0dB - 110 = 3dB - 111 = 6dB - */ - wmcodec_write(LADCBOOST,0x50); - wmcodec_write(RADCBOOST,0x50); - - /* Set L/R input PGA Volume to 0db */ - // wm8758_write(LINPGAVOL,0x3f); - // wm8758_write(RINPGAVOL,0x13f); - - /* Enable monitoring */ - wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/ - wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/ - - audiohw_mute(0); -} - -void audiohw_disable_recording(void) { - audiohw_mute(1); - - wmcodec_write(PWRMGMT3, 0x0); - - wmcodec_write(PWRMGMT1, 0x0); - - wmcodec_write(PWRMGMT2, 0x40); -} - -void audiohw_set_recvol(int left, int right, int type) { - - (void)left; - (void)right; - (void)type; -} - -void audiohw_set_monitor(int enable) { - - (void)enable; -} - -void audiohw_set_equalizer_band(int band, int freq, int bw, int gain) -{ - unsigned int eq = 0; - - /* Band 1..3 are peak filters */ - if (band >= 1 && band <= 3) { - eq |= (bw << 8); - } - - eq |= (freq << 5); - eq |= 12 - gain; - - if (band == 0) { - wmcodec_write(EQ1, eq | 0x100); /* Always apply EQ to the DAC path */ - } else if (band == 1) { - wmcodec_write(EQ2, eq); - } else if (band == 2) { - wmcodec_write(EQ3, eq); - } else if (band == 3) { - wmcodec_write(EQ4, eq); - } else if (band == 4) { - wmcodec_write(EQ5, eq); - } -} diff --git a/firmware/drivers/wm8975.c b/firmware/drivers/wm8975.c deleted file mode 100644 index 9052236131..0000000000 --- a/firmware/drivers/wm8975.c +++ /dev/null @@ -1,318 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Driver for WM8975 audio codec - * - * Based on code from the ipodlinux project - http://ipodlinux.org/ - * Adapted for Rockbox in December 2005 - * - * Original file: linux/arch/armnommu/mach-ipod/audio.c - * - * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "power.h" -#include "debug.h" -#include "system.h" -#include "sprintf.h" -#include "button.h" -#include "string.h" -#include "file.h" -#include "buffer.h" -#include "audio.h" - -#include "wmcodec.h" -#include "wm8975.h" -#include "i2s.h" - -/* use zero crossing to reduce clicks during volume changes */ -#define VOLUME_ZC_WAIT (1<<7) - - - -/* convert tenth of dB volume (-730..60) to master volume register value */ -int tenthdb2master(int db) -{ - /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ - /* 1111111 == +6dB (0x7f) */ - /* 1111001 == 0dB (0x79) */ - /* 0110000 == -73dB (0x30 */ - /* 0101111..0000000 == mute (0x2f) */ - - if (db < VOLUME_MIN) { - return 0x0; - } else { - return((db/10)+73+0x30); - } -} - -/* convert tenth of dB volume (-780..0) to mixer volume register value */ -int tenthdb2mixer(int db) -{ - (void)db; - return 0; -} - - -void audiohw_reset(void); - -#define IPOD_PCM_LEVEL 0x65 /* -6dB */ - - -/* Silently enable / disable audio output */ -void audiohw_enable_output(bool enable) -{ - if (enable) - { - /* reset the I2S controller into known state */ - i2s_reset(); - - /* - * 1. Switch on power supplies. - * By default the WM8750L is in Standby Mode, the DAC is - * digitally muted and the Audio Interface, Line outputs - * and Headphone outputs are all OFF (DACMU = 1 Power - * Management registers 1 and 2 are all zeros). - */ - wmcodec_write(RESET, 0x1ff); /*Reset*/ - wmcodec_write(RESET, 0x0); - - /* 2. Enable Vmid and VREF. */ - wmcodec_write(PWRMGMT1, 0xc0); /*Pwr Mgmt(1)*/ - - /* From app notes: allow Vref to stabilize to reduce clicks */ - sleep(HZ/4); - - /* 3. Enable DACs as required. */ - wmcodec_write(PWRMGMT2, 0x180); /*Pwr Mgmt(2)*/ - - /* 4. Enable line and / or headphone output buffers as required. */ - wmcodec_write(PWRMGMT2, 0x1f8); /*Pwr Mgmt(2)*/ - - /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ - /* IWL=00(16 bit) FORMAT=10(I2S format) */ - wmcodec_write(AINTFCE, 0x42); - - /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ - audiohw_set_sample_rate(WM8975_44100HZ); - - /* set the volume to -6dB */ - wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | IPOD_PCM_LEVEL); - wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | IPOD_PCM_LEVEL); - - wmcodec_write(LOUTMIX1, 0x150); /* Left out Mix(def) */ - wmcodec_write(LOUTMIX2, 0x50); - - wmcodec_write(ROUTMIX1, 0x50); /* Right out Mix(def) */ - wmcodec_write(ROUTMIX2, 0x150); - - wmcodec_write(MOUTMIX1, 0x0); /* Mono out Mix */ - wmcodec_write(MOUTMIX2, 0x0); - - audiohw_mute(0); - } else { - audiohw_mute(1); - } -} - - - -int audiohw_set_master_vol(int vol_l, int vol_r) -{ - /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ - /* 1111111 == +6dB */ - /* 1111001 == 0dB */ - /* 0110000 == -73dB */ - /* 0101111 == mute (0x2f) */ - - /* OUT1 */ - wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | vol_l); - wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); - - return 0; -} - -int audiohw_set_lineout_vol(int vol_l, int vol_r) -{ - /* OUT2 */ - wmcodec_write(LOUT2VOL, VOLUME_ZC_WAIT | vol_l); - wmcodec_write(ROUT2VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); - - return 0; -} - -int audiohw_set_mixer_vol(int channel1, int channel2) -{ - (void)channel1; - (void)channel2; - - return 0; -} - -void audiohw_set_bass(int value) -{ - const int regvalues[] = { - 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 - }; - - if ((value >= -6) && (value <= 9)) { - /* We use linear bass control with 200 Hz cutoff */ - wmcodec_write(BASSCTRL, regvalues[value + 6] | 0x40); - } -} - -void audiohw_set_treble(int value) -{ - const int regvalues[] = { - 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 - }; - - if ((value >= -6) && (value <= 9)) { - /* We use linear treble control with 4 kHz cutoff */ - wmcodec_write(TREBCTRL, regvalues[value + 6] | 0x40); - } -} - -int audiohw_mute(int mute) -{ - if (mute) - { - /* Set DACMU = 1 to soft-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x8); - } else { - /* Set DACMU = 0 to soft-un-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x0); - } - - return 0; -} - -/* Nice shutdown of WM8975 codec */ -void audiohw_close(void) -{ - /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ - wmcodec_write(DACCTRL, 0x8); - - /* 2. Disable all output buffers. */ - wmcodec_write(PWRMGMT2, 0x0); /*Pwr Mgmt(2)*/ - - /* 3. Switch off the power supplies. */ - wmcodec_write(PWRMGMT1, 0x0); /*Pwr Mgmt(1)*/ -} - -/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ -void audiohw_set_nsorder(int order) -{ - (void)order; -} - -/* Note: Disable output before calling this function */ -void audiohw_set_sample_rate(int sampling_control) { - - wmcodec_write(0x08, sampling_control); - -} - -void audiohw_enable_recording(bool source_mic) -{ - (void)source_mic; - - /* reset the I2S controller into known state */ - i2s_reset(); - - /* - * 1. Switch on power supplies. - * By default the WM8750L is in Standby Mode, the DAC is - * digitally muted and the Audio Interface, Line outputs - * and Headphone outputs are all OFF (DACMU = 1 Power - * Management registers 1 and 2 are all zeros). - */ - wmcodec_write(0x0f, 0x1ff); - wmcodec_write(0x0f, 0x000); - - /* 2. Enable Vmid and VREF. */ - wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/ - - /* 3. Enable ADCs as required. */ - wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/ - wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/ - - /* 4. Enable line and / or headphone output buffers as required. */ - wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/ - - /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ - /* IWL=00(16 bit) FORMAT=10(I2S format) */ - wmcodec_write(0x07, 0x42); - - /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ - audiohw_set_sample_rate(WM8975_44100HZ); - - /* unmute inputs */ - wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */ - wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */ - - wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */ - wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */ - - if (source_mic) { - /* VSEL=10(def) DATSEL=10 (use right ADC only) */ - wmcodec_write(0x17, 0xc9); /* Additional control(1) */ - - /* VROI=1 (sets output resistance to 40kohms) */ - wmcodec_write(0x1b, 0x40); /* Additional control(3) */ - - /* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */ - wmcodec_write(0x20, 0x60); /* ADCL signal path */ - wmcodec_write(0x21, 0x60); /* ADCR signal path */ - } else { - /* VSEL=10(def) DATSEL=00 (left->left, right->right) */ - wmcodec_write(0x17, 0xc1); /* Additional control(1) */ - - /* VROI=1 (sets output resistance to 40kohms) */ - wmcodec_write(0x1b, 0x40); /* Additional control(3) */ - - /* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */ - wmcodec_write(0x20, 0x00); /* ADCL signal path */ - /* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */ - wmcodec_write(0x21, 0x00); /* ADCR signal path */ - } -} - -void audiohw_disable_recording(void) { - /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ - wmcodec_write(0x05, 0x8); - - /* 2. Disable all output buffers. */ - wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/ - - /* 3. Switch off the power supplies. */ - wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/ -} - -void audiohw_set_recvol(int left, int right, int type) { - - (void)left; - (void)right; - (void)type; -} - -void audiohw_set_monitor(int enable) { - - (void)enable; -} -- cgit v1.2.3