From 15b7321fe1345a9efd296fe135f19e1da45f0e7c Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Tue, 2 Oct 2007 07:48:50 +0000 Subject: Split wm8731 and wm8721 drivers. wm8721 can be much simpler since it has no recording. Provide reg bit definitions for those. Add some temporary hacks pcm-pp to prevent crashing when playing after recording. Make playback start after recording on pp5020. Get wm8731 to monitor recording but plans are to do that digitally. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14948 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 6 +- firmware/drivers/audio/wm8721.c | 190 +++++++++++++++++++++++ firmware/drivers/audio/wm8731.c | 324 +++++++++++++++++++++++++++++++++++++++ firmware/drivers/audio/wm8731l.c | 310 ------------------------------------- firmware/export/audiohw.h | 6 +- firmware/export/wm8731.h | 141 +++++++++++++++++ firmware/export/wm8731l.h | 65 -------- firmware/sound.c | 4 +- firmware/target/arm/pcm-pp.c | 49 ++++-- firmware/target/arm/wmcodec-pp.c | 10 +- 10 files changed, 709 insertions(+), 396 deletions(-) create mode 100644 firmware/drivers/audio/wm8721.c create mode 100644 firmware/drivers/audio/wm8731.c delete mode 100644 firmware/drivers/audio/wm8731l.c create mode 100644 firmware/export/wm8731.h delete mode 100644 firmware/export/wm8731l.h diff --git a/firmware/SOURCES b/firmware/SOURCES index 72712b6b6c..1079fabec9 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -214,8 +214,10 @@ drivers/audio/wm8751.c drivers/audio/wm8975.c #elif defined(HAVE_WM8758) drivers/audio/wm8758.c -#elif defined(HAVE_WM8731) || defined(HAVE_WM8721) -drivers/audio/wm8731l.c +#elif defined(HAVE_WM8721) +drivers/audio/wm8721.c +#elif defined(HAVE_WM8731) +drivers/audio/wm8731.c #elif defined(HAVE_AS3514) drivers/audio/as3514.c #elif defined(HAVE_TLV320) diff --git a/firmware/drivers/audio/wm8721.c b/firmware/drivers/audio/wm8721.c new file mode 100644 index 0000000000..9b58454ca8 --- /dev/null +++ b/firmware/drivers/audio/wm8721.c @@ -0,0 +1,190 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for WM8721 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 "config.h" +#include "logf.h" +#include "system.h" +#include "string.h" +#include "audio.h" + +#include "wmcodec.h" +#include "audiohw.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) + +const struct sound_settings_info audiohw_settings[] = { + [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, + /* HAVE_SW_TONE_CONTROLS */ + [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, + [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, + [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, +}; + +/* 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; +} + +void audiohw_mute(bool 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); + } +} + +/** 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); + + /* DACSEL=1 */ + wmcodec_write(0x4, 0x10); + + /* 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(WM8721_USB24_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); + + 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) */ + wmcodec_write(LOUTVOL, VOLUME_ZC_WAIT | vol_l); + wmcodec_write(ROUTVOL, VOLUME_ZC_WAIT | vol_r); + + return 0; +} + +/* Nice shutdown of WM8721 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); +} diff --git a/firmware/drivers/audio/wm8731.c b/firmware/drivers/audio/wm8731.c new file mode 100644 index 0000000000..2e1a978777 --- /dev/null +++ b/firmware/drivers/audio/wm8731.c @@ -0,0 +1,324 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "config.h" +#include "logf.h" +#include "system.h" +#include "string.h" +#include "audio.h" + +#include "wmcodec.h" +#include "audiohw.h" +#include "i2s.h" + +const struct sound_settings_info audiohw_settings[] = { + [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, + /* HAVE_SW_TONE_CONTROLS */ + [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, + [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, + [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, +#ifdef HAVE_RECORDING + [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23}, + [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23}, + [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 0}, +#endif +}; + +/* Init values/shadows + * Ignore bit 8 since that only specifies "both" for updating + * gains */ +static unsigned char wm8731_regs[7] = +{ + [LINVOL] = LINVOL_LINMUTE, + [RINVOL] = RINVOL_RINMUTE, + [LOUTVOL] = ROUTVOL_RZCEN, + [ROUTVOL] = ROUTVOL_RZCEN, + [AAPCTRL] = AAPCTRL_MUTEMIC | AAPCTRL_DACSEL, + [DAPCTRL] = DAPCTRL_DACMU | DAPCTRL_DEEMP_44KHz | DAPCTRL_ADCHPD, + [PDCTRL] = PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_ADCPD | + PDCTRL_OUTPD | PDCTRL_OSCPD | PDCTRL_CLKOUTPD, +}; + +static void wm8731_write(int reg, unsigned val) +{ + wm8731_regs[reg] = (unsigned char)val; + wmcodec_write(reg, val); +} + +static void wm8731_write_and(int reg, unsigned bits) +{ + wm8731_write(reg, wm8731_regs[reg] & bits); +} + +static void wm8731_write_or(int reg, unsigned bits) +{ + wm8731_write(reg, wm8731_regs[reg] | bits); +} + +/* 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 sound_val2phys(int setting, int value) +{ + int result; + + switch(setting) + { + case SOUND_LEFT_GAIN: + case SOUND_RIGHT_GAIN: + result = (value - 23) * 15; + break; + case SOUND_MIC_GAIN: + result = value * 200; + break; + default: + result = value; + break; + } + + return result; +} + +void audiohw_mute(bool mute) +{ + if (mute) { + /* Set DACMU = 1 to soft-mute the audio DACs. */ + wm8731_write_or(DAPCTRL, DAPCTRL_DACMU); + } else { + /* Set DACMU = 0 to soft-un-mute the audio DACs. */ + wm8731_write_and(DAPCTRL, ~DAPCTRL_DACMU); + } +} + +static void codec_set_active(int active) +{ + /* set active to 0x0 or 0x1 */ + wmcodec_write(ACTIVECTRL, active ? ACTIVECTRL_ACTIVE : 0); +} + +void audiohw_preinit(void) +{ + i2s_reset(); + + /* POWER UP SEQUENCE */ + /* 1) Switch on power supplies. By default the WM8731 is in Standby Mode, + * the DAC is digitally muted and the Audio Interface and Outputs are + * all OFF. */ + wmcodec_write(RESET, RESET_RESET); + + /* 2) Set all required bits in the Power Down register (0Ch) to '0'; + * EXCEPT the OUTPD bit, this should be set to '1' (Default). */ + wm8731_write(PDCTRL, wm8731_regs[PDCTRL]); + + /* 3) Set required values in all other registers except 12h (Active). */ + wmcodec_write(AINTFCE, AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT | + AINTFCE_MS); + wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); + wm8731_write(DAPCTRL, wm8731_regs[DAPCTRL]); + wmcodec_write(SAMPCTRL, WM8731_USB24_44100HZ); + + /* 5) The last write of the sequence should be setting OUTPD to '0' + * (active) in register 0Ch, enabling the DAC signal path, free + * of any significant power-up noise. */ + wm8731_write_and(PDCTRL, ~PDCTRL_OUTPD); +} + +void audiohw_postinit(void) +{ + sleep(HZ); + + /* 4) Set the ‘Active’ bit in register 12h. */ + codec_set_active(true); + + audiohw_mute(false); + +#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 +} + +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) */ + wm8731_write(LOUTVOL, LOUTVOL_LZCEN | (vol_l & LOUTVOL_LHPVOL_MASK)); + wm8731_write(ROUTVOL, ROUTVOL_RZCEN | (vol_r & ROUTVOL_RHPVOL_MASK)); + return 0; +} + +/* Nice shutdown of WM8731 codec */ +void audiohw_close(void) +{ + /* POWER DOWN SEQUENCE */ + /* 1) Set the OUTPD bit to '1' (power down). */ + wm8731_write_or(PDCTRL, PDCTRL_OUTPD); + /* 2) Remove the WM8731 supplies. */ +} + +void audiohw_set_nsorder(int order) +{ + static const unsigned char deemp[4] = + { + DAPCTRL_DEEMP_DISABLE, + DAPCTRL_DEEMP_32KHz, + DAPCTRL_DEEMP_44KHz, + DAPCTRL_DEEMP_48KHz + }; + + if ((unsigned)order >= ARRAYLEN(deemp)) + order = 0; + + wm8731_write(DAPCTRL, + (wm8731_regs[DAPCTRL] & ~DAPCTRL_DEEMP_MASK) | deemp[order]); +} + +void audiohw_set_sample_rate(int sampling_control) +{ + codec_set_active(false); + wmcodec_write(SAMPCTRL, sampling_control); + codec_set_active(true); +} + +void audiohw_enable_recording(bool source_mic) +{ + codec_set_active(false); + + wm8731_regs[PDCTRL] &= ~PDCTRL_ADCPD; + wm8731_regs[PDCTRL] |= PDCTRL_DACPD; + wm8731_regs[AAPCTRL] &= ~AAPCTRL_DACSEL; + + if (source_mic) { + wm8731_write_or(LINVOL, LINVOL_LINMUTE); + wm8731_write_or(RINVOL, RINVOL_RINMUTE); + wm8731_regs[PDCTRL] &= ~PDCTRL_MICPD; + wm8731_regs[PDCTRL] |= PDCTRL_LINEINPD; + wm8731_regs[AAPCTRL] |= AAPCTRL_INSEL | AAPCTRL_SIDETONE; + wm8731_regs[AAPCTRL] &= ~AAPCTRL_MUTEMIC; + } else { + wm8731_regs[PDCTRL] |= PDCTRL_MICPD; + wm8731_regs[PDCTRL] &= ~PDCTRL_LINEINPD; + wm8731_regs[AAPCTRL] |= AAPCTRL_MUTEMIC | AAPCTRL_BYPASS; + wm8731_regs[AAPCTRL] &= ~(AAPCTRL_INSEL | AAPCTRL_SIDETONE); + } + + wm8731_write(PDCTRL, wm8731_regs[PDCTRL]); + wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); + + if (!source_mic) { + wm8731_regs[AAPCTRL] |= AAPCTRL_INSEL | AAPCTRL_SIDETONE; + wm8731_regs[AAPCTRL] &= ~(AAPCTRL_MUTEMIC | AAPCTRL_BYPASS); + } else { + wm8731_write_and(LINVOL, ~LINVOL_LINMUTE); + wm8731_write_and(RINVOL, ~RINVOL_RINMUTE); + } + + codec_set_active(true); +} + +void audiohw_disable_recording(void) +{ + codec_set_active(false); + + /* Mute inputs */ + wm8731_write_or(LINVOL, LINVOL_LINMUTE); + wm8731_write_or(RINVOL, RINVOL_RINMUTE); + wm8731_write_or(AAPCTRL, AAPCTRL_MUTEMIC); + + /* Turn off input analog audio paths */ + wm8731_regs[AAPCTRL] &= ~(AAPCTRL_BYPASS | AAPCTRL_SIDETONE); + wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); + + /* Set power config */ + wm8731_regs[PDCTRL] &= ~PDCTRL_DACPD; + wm8731_regs[PDCTRL] |= PDCTRL_MICPD | PDCTRL_LINEINPD | + PDCTRL_ADCPD; + wm8731_write(PDCTRL, wm8731_regs[PDCTRL]); + + /* Select DAC */ + wm8731_write_or(AAPCTRL, AAPCTRL_DACSEL); + + codec_set_active(true); +} + +void audiohw_set_recvol(int left, int right, int type) +{ + switch (type) + { + case AUDIO_GAIN_MIC: + if (left > 0) { + wm8731_write_or(AAPCTRL, AAPCTRL_MIC_BOOST); + } + else { + wm8731_write_and(AAPCTRL, ~AAPCTRL_MIC_BOOST); + } + break; + case AUDIO_GAIN_LINEIN: + wm8731_regs[LINVOL] &= ~LINVOL_MASK; + wm8731_write(LINVOL, wm8731_regs[LINVOL] | (left & LINVOL_MASK)); + wm8731_regs[RINVOL] &= ~RINVOL_MASK; + wm8731_write(RINVOL, wm8731_regs[RINVOL] | (right & RINVOL_MASK)); + break; + default: + return; + } +} + +void audiohw_set_monitor(int enable) +{ + /* TODO: Implement for FM monitoring */ + (void)enable; +} diff --git a/firmware/drivers/audio/wm8731l.c b/firmware/drivers/audio/wm8731l.c deleted file mode 100644 index 94efc535e2..0000000000 --- a/firmware/drivers/audio/wm8731l.c +++ /dev/null @@ -1,310 +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 "config.h" -#include "logf.h" -#include "system.h" -#include "string.h" -#include "audio.h" - -#include "wmcodec.h" -#include "audiohw.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) - -const struct sound_settings_info audiohw_settings[] = { - [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, - /* HAVE_SW_TONE_CONTROLS */ - [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, - [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, - [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, - [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, - [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, -#ifdef HAVE_RECORDING - [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0}, - [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0}, - [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16}, -#endif -}; - -/* 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; -} - -void audiohw_mute(bool 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); - } -} - -/** 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/export/audiohw.h b/firmware/export/audiohw.h index ec0177d091..9da1a3875f 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -31,8 +31,10 @@ #include "wm8975.h" #elif defined(HAVE_WM8758) #include "wm8758.h" -#elif defined(HAVE_WM8731) || defined(HAVE_WM8721) -#include "wm8731l.h" +#elif defined(HAVE_WM8721) +#include "wm8721.h" +#elif defined(HAVE_WM8731) +#include "wm8731.h" #elif defined(HAVE_TLV320) #include "tlv320.h" #elif defined(HAVE_AS3514) diff --git a/firmware/export/wm8731.h b/firmware/export/wm8731.h new file mode 100644 index 0000000000..3fc6bc7a5a --- /dev/null +++ b/firmware/export/wm8731.h @@ -0,0 +1,141 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * + * 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. + * + ****************************************************************************/ + +#ifndef _WM8731_H +#define _WM8731_H + +/* volume/balance/treble/bass interdependency */ +#define VOLUME_MIN -730 +#define VOLUME_MAX 60 + +extern int tenthdb2master(int db); +extern int tenthdb2mixer(int db); + +extern void audiohw_reset(void); +extern void audiohw_preinit(void); +extern void audiohw_postinit(void); +extern int audiohw_set_master_vol(int vol_l, int vol_r); +extern void audiohw_set_nsorder(int order); +extern void audiohw_set_sample_rate(int sampling_control); + +extern void audiohw_enable_recording(bool source_mic); +extern void audiohw_disable_recording(void); +extern void audiohw_set_recvol(int left, int right, int type); +extern void audiohw_set_monitor(int enable); + +/* Register addresses and bits */ +#define LINVOL 0x00 +#define LINVOL_MASK 0x1f +#define LINVOL_LRINBOTH (1 << 8) +#define LINVOL_LINMUTE (1 << 7) + +#define RINVOL 0x01 +#define RINVOL_MASK 0x1f +#define RINVOL_RINMUTE (1 << 7) +#define RINVOL_RLINBOTH (1 << 8) + +#define LOUTVOL 0x02 +#define LOUTVOL_LHPVOL_MASK 0x7f +#define LOUTVOL_LZCEN (1 << 7) +#define LOUTVOL_LRHP_BOTH (1 << 8) + +#define ROUTVOL 0x03 +#define ROUTVOL_RHPVOL_MASK 0x7f +#define ROUTVOL_RZCEN (1 << 7) +#define ROUTVOL_RLHP_BOTH (1 << 8) + +#define AAPCTRL 0x04 /* Analog audio path control */ +#define AAPCTRL_MIC_BOOST (1 << 0) +#define AAPCTRL_MUTEMIC (1 << 1) +#define AAPCTRL_INSEL (1 << 2) +#define AAPCTRL_BYPASS (1 << 3) +#define AAPCTRL_DACSEL (1 << 4) +#define AAPCTRL_SIDETONE (1 << 5) +#define AAPCTRL_SIDEATT_6dB (3 << 6) +#define AAPCTRL_SIDEATT_9dB (1 << 6) +#define AAPCTRL_SIDEATT_12dB (2 << 6) +#define AAPCTRL_SIDEATT_15dB (3 << 6) + +#define DAPCTRL 0x05 /* Digital audio path control */ +#define DAPCTRL_ADCHPD (1 << 0) +#define DAPCTRL_DEEMP_DISABLE (0 << 2) +#define DAPCTRL_DEEMP_32KHz (1 << 2) +#define DAPCTRL_DEEMP_44KHz (2 << 2) +#define DAPCTRL_DEEMP_48KHz (3 << 2) +#define DAPCTRL_DEEMP_MASK (3 << 2) +#define DAPCTRL_DACMU (1 << 3) +#define DAPCTRL_HPOR (1 << 4) + +#define PDCTRL 0x06 +#define PDCTRL_LINEINPD (1 << 0) +#define PDCTRL_MICPD (1 << 1) +#define PDCTRL_ADCPD (1 << 2) +#define PDCTRL_DACPD (1 << 3) +#define PDCTRL_OUTPD (1 << 4) +#define PDCTRL_OSCPD (1 << 5) +#define PDCTRL_CLKOUTPD (1 << 6) +#define PDCTRL_POWEROFF (1 << 7) + +#define AINTFCE 0x07 +#define AINTFCE_FORMAT_MSB_RJUST (0 << 0) +#define AINTFCE_FORMAT_MSB_LJUST (1 << 0) +#define AINTFCE_FORMAT_I2S (2 << 0) +#define AINTFCE_FORMAT_DSP (3 << 0) +#define AINTFCE_FORMAT_MASK (3 << 0) +#define AINTFCE_IWL_16BIT (0 << 2) +#define AINTFCE_IWL_20BIT (1 << 2) +#define AINTFCE_IWL_24BIT (2 << 2) +#define AINTFCE_IWL_32BIT (3 << 2) +#define AINTFCE_IWL_MASK (3 << 2) +#define AINTFCE_LRP_I2S_RLO (0 << 4) +#define AINTFCE_LRP_I2S_RHI (1 << 4) +#define AINTFCE_DSP_MODE_A (0 << 4) +#define AINTFCE_DSP_MODE_B (1 << 4) +#define AINTFCE_LRSWAP (1 << 5) +#define AINTFCE_MS (1 << 6) +#define AINTFCE_BCLKINV (1 << 7) + +#define SAMPCTRL 0x08 +#define SAMPCTRL_USB (1 << 0) +#define SAMPCTRL_BOSR_NOR_256fs (0 << 1) +#define SAMPCTRL_BOSR_NOR_384fs (1 << 1) +#define SAMPCTRL_BOSR_USB_250fs (0 << 1) +#define SAMPCTRL_BOSR_USB_272fs (1 << 1) +/* Bits 2-5: + * Sample rate setting are device-specific. See WM8731(L) datasheet + * for proper settings for the device's clocking */ +#define SAMPCTRL_SR_MASK (0xf << 2) +#define SAMPCTRL_CLKIDIV2 (1 << 6) +#define SAMPCTRL_CLKODIV2 (1 << 7) + +#define ACTIVECTRL 0x09 +#define ACTIVECTRL_ACTIVE (1 << 0) + +#define RESET 0x0f +#define RESET_RESET 0x0 + +/* SAMPCTRL values for the supported samplerates (24MHz MCLK/USB): */ +#define WM8731_USB24_8000HZ 0x4d +#define WM8731_USB24_32000HZ 0x59 +#define WM8731_USB24_44100HZ 0x63 +#define WM8731_USB24_48000HZ 0x41 +#define WM8731_USB24_88200HZ 0x7f +#define WM8731_USB24_96000HZ 0x5d + +#endif /* _WM8731_H */ diff --git a/firmware/export/wm8731l.h b/firmware/export/wm8731l.h deleted file mode 100644 index f0f63c909a..0000000000 --- a/firmware/export/wm8731l.h +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 by Dave Chapman - * - * 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. - * - ****************************************************************************/ - -#ifndef _WM8731L_H -#define _WM8731L_H - -/* volume/balance/treble/bass interdependency */ -#define VOLUME_MIN -730 -#define VOLUME_MAX 60 - -extern int tenthdb2master(int db); -extern int tenthdb2mixer(int db); - -extern void audiohw_reset(void); -extern void audiohw_enable_output(bool enable); -extern int audiohw_set_master_vol(int vol_l, int vol_r); -extern int audiohw_set_mixer_vol(int channel1, int channel2); -extern void audiohw_set_bass(int value); -extern void audiohw_set_treble(int value); -extern void audiohw_set_nsorder(int order); -extern void audiohw_set_sample_rate(int sampling_control); - -extern void audiohw_enable_recording(bool source_mic); -extern void audiohw_disable_recording(void); -extern void audiohw_set_recvol(int left, int right, int type); -extern void audiohw_set_monitor(int enable); - -/* Register addresses */ -#define LINVOL 0x00 -#define RINVOL 0x01 -#define LOUTVOL 0x02 -#define ROUTVOL 0x03 -#define AAPCTRL 0x04 /* Analog audio path control */ -#define DACCTRL 0x05 -#define PWRMGMT 0x06 -#define AINTFCE 0x07 -#define SAMPCTRL 0x08 -#define ACTIVECTRL 0x09 -#define RESET 0x0f - -/* Register settings for the supported samplerates: */ -#define WM8731L_8000HZ 0x4d -#define WM8731L_32000HZ 0x59 -#define WM8731L_44100HZ 0x63 -#define WM8731L_48000HZ 0x41 -#define WM8731L_88200HZ 0x7f -#define WM8731L_96000HZ 0x5d - -#endif /* _WM8975_H */ diff --git a/firmware/sound.c b/firmware/sound.c index 8b68a5569b..335aa1a640 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -744,7 +744,7 @@ void sound_set(int setting, int value) sound_set_val(value); } -#if !defined(HAVE_AS3514) || defined(SIMULATOR) +#if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731)) || defined(SIMULATOR) int sound_val2phys(int setting, int value) { #if CONFIG_CODEC == MAS3587F @@ -782,7 +782,7 @@ int sound_val2phys(int setting, int value) break; } return result; -#elif defined(HAVE_TLV320) +#elif defined(HAVE_TLV320) || defined(HAVE_WM8751) int result = 0; switch(setting) diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c index 5ac15fe00c..42b9aeb6cb 100644 --- a/firmware/target/arm/pcm-pp.c +++ b/firmware/target/arm/pcm-pp.c @@ -168,7 +168,8 @@ void fiq(void) do { while (p_size) { - if (FIFO_FREE_COUNT < 2) { + //if (FIFO_FREE_COUNT < 2) { + if (((IISFIFO_CFG & (0x1f << 16)) >> 16) < 2) { /* Enable interrupt */ #ifdef CPU_PP502x IISCONFIG |= (1 << 1); @@ -219,8 +220,10 @@ void pcm_play_dma_start(const void *addr, size_t size) set_fiq_handler(fiq); enable_fiq(); +#if CONFIG_CPU == PP5020 + /* Do nothing */ +#elif defined(CPU_PP502x) /* Enable playback FIFO */ -#ifdef CPU_PP502x IISCONFIG |= (1 << 29); #elif CONFIG_CPU == PP5002 IISCONFIG |= 0x4; @@ -257,11 +260,13 @@ void pcm_play_dma_stop(void) if (!audio_status()) pcm_paused = false; -#ifdef CPU_PP502x +#if CONFIG_CPU == PP5020 + /* Disable TX interrupt */ + IISCONFIG &= ~(1 << 1); +#elif defined(CPU_PP502x) /* Disable playback FIFO and interrupt */ IISCONFIG &= ~((1 << 29) | (1 << 1)); #elif CONFIG_CPU == PP5002 - /* Disable playback FIFO */ IISCONFIG &= ~0x4; @@ -274,7 +279,10 @@ void pcm_play_dma_stop(void) void pcm_play_pause_pause(void) { -#ifdef CPU_PP502x +#if CONFIG_CPU == PP5020 + /* Disable TX interrupt */ + IISCONFIG &= ~(1 << 1); +#elif defined(CPU_PP502x) /* Disable playback FIFO and interrupt */ IISCONFIG &= ~((1 << 29) | (1 << 1)); #elif CONFIG_CPU == PP5002 @@ -293,8 +301,10 @@ void pcm_play_pause_unpause(void) set_fiq_handler(fiq); enable_fiq(); +#if CONFIG_CPU == PP5020 + /* Do nothing */ +#elif defined(CPU_PP502x) /* Enable playback FIFO */ -#ifdef CPU_PP502x IISCONFIG |= (1 << 29); #elif CONFIG_CPU == PP5002 IISCONFIG |= 0x4; @@ -344,14 +354,20 @@ void pcm_init(void) /* Initialize default register values. */ audiohw_init(); +#ifndef HAVE_WM8731 /* Power on */ audiohw_enable_output(true); - /* Unmute the master channel (DAC should be at zero point now). */ audiohw_mute(false); +#endif /* Call pcm_play_dma_stop to initialize everything. */ pcm_play_dma_stop(); + +#if CONFIG_CPU == PP5020 + /* This processor doesn't like this disabled */ + IISCONFIG |= (1 << 29); +#endif } void pcm_postinit(void) @@ -438,12 +454,15 @@ fiq_record_exit: #else static short peak_l, peak_r IBSS_ATTR; -void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); +/* Temporary to stop playback crashing after record */ +void fiq_record(void) ICODE_ATTR __attribute__((naked)); void fiq_record(void) { - short value; - pcm_more_callback_type2 more_ready; - int status = 0; + asm volatile ("stmfd sp!, {r0-r7, r11, ip, lr} \n"); /* Store context */ + + register short value; + register pcm_more_callback_type2 more_ready; + register int status = 0; /* Clear interrupt */ #ifdef CPU_PP502x @@ -460,7 +479,7 @@ void fiq_record(void) #elif CONFIG_CPU == PP5002 /* TODO */ #endif - return; + goto fiq_record_exit; } value = (unsigned short)(IISFIFO_RD >> 16); @@ -486,10 +505,14 @@ void fiq_record(void) more_ready = pcm_callback_more_ready; if (more_ready != NULL && more_ready(status) >= 0) - return; + goto fiq_record_exit; /* Finished recording */ pcm_rec_dma_stop(); + +fiq_record_exit: + asm volatile("ldmfd sp!, {r0-r7, r11, ip, lr} \n" /* Restore context */ + "subs pc, lr, #4 \n"); /* Return from FIQ */ } #endif /* HAVE_AS3514 */ diff --git a/firmware/target/arm/wmcodec-pp.c b/firmware/target/arm/wmcodec-pp.c index 455e3e1087..a2c83f33b3 100644 --- a/firmware/target/arm/wmcodec-pp.c +++ b/firmware/target/arm/wmcodec-pp.c @@ -25,6 +25,7 @@ ****************************************************************************/ #include "system.h" +#include "audiohw.h" #include "i2c-pp.h" #if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) @@ -39,7 +40,7 @@ /* * Initialise the PP I2C and I2S. */ -int audiohw_init(void) { +void audiohw_init(void) { /* reset I2C */ i2c_init(); @@ -95,12 +96,17 @@ int audiohw_init(void) { #endif /* IPOD_1G2G/3G */ #endif - return 0; +#ifdef HAVE_WM8731 + audiohw_preinit(); +#endif + } +#ifndef HAVE_WM8731 void audiohw_postinit(void) { } +#endif void wmcodec_write(int reg, int data) { -- cgit v1.2.3