From 3b703391f9584c9df322bc08d2e12369b88503a4 Mon Sep 17 00:00:00 2001 From: wodz Date: Fri, 2 Jul 2010 21:09:28 +0000 Subject: [PATCH] HD200 - Setup codec as I2S master and enable recording git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27250 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/audio/wm8751.c | 153 +++++++++++++++++++---------- firmware/export/config/mpiohd200.h | 32 +++--- firmware/export/wm8751.h | 10 +- firmware/target/coldfire/mpio/audio-mpio.c | 7 +- firmware/target/coldfire/pcm-coldfire.c | 13 ++- 5 files changed, 137 insertions(+), 78 deletions(-) diff --git a/firmware/drivers/audio/wm8751.c b/firmware/drivers/audio/wm8751.c index 2adbdcaa56..6e37a91ed7 100644 --- a/firmware/drivers/audio/wm8751.c +++ b/firmware/drivers/audio/wm8751.c @@ -42,6 +42,14 @@ const struct sound_settings_info audiohw_settings[] = { [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, +#ifdef AUDIOHW_HAVE_DEPTH_3D + [SOUND_DEPTH_3D] = {"", 0, 1, 0, 15, 0}, +#endif +#ifdef HAVE_RECORDING + [SOUND_LEFT_GAIN] = {"dB", 1, 1,-172, 300, 0}, + [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-172, 300, 0}, + [SOUND_MIC_GAIN] = {"dB", 1, 1,-172, 300, 0}, +#endif }; /* Flags used in combination with settings */ @@ -110,7 +118,7 @@ static int recvol2hw(int value) /* 010111 == 0dB (0x17) */ /* 000000 == -17.25dB */ - return (3*(value/10 - 0x17))/4; + return ((4*(value))/30 + 0x17); } #endif static void audiohw_mute(bool mute) @@ -167,6 +175,14 @@ void audiohw_postinit(void) /* 4. Enable line and / or headphone output buffers as required. */ #if defined(MROBE_100) || defined(MPIO_HD200) + /* fix for high pitch noise after power-up on HD200 + * it is *NOT* required step according to the + * Datasheet for WM8750L but real life is different :-) + */ + wmcodec_write(LOUT1, LOUT1_BITS); + wmcodec_write(ROUT1, ROUT1_BITS); + + /* power-up output stage */ wmcodec_write(PWRMGMT2, PWRMGMT2_DACL | PWRMGMT2_DACR | PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1); #else @@ -196,16 +212,6 @@ void audiohw_postinit(void) #endif #endif -#ifdef MPIO_HD200 - /* Crude fix for high pitch noise at startup - * I should find out what realy causes this - */ - wmcodec_write(LOUT1, LOUT1_BITS|0x7f); - wmcodec_write(ROUT1, ROUT1_BITS|0x7f); - wmcodec_write(LOUT1, LOUT1_BITS); - wmcodec_write(ROUT1, ROUT1_BITS); -#endif - /* lower power consumption */ wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); @@ -276,10 +282,12 @@ void audiohw_close(void) wmcodec_write(PWRMGMT1, 0x0); } +/* According to datasheet of WM8750 + * clocking setup is needed in both slave and master mode + */ void audiohw_set_frequency(int fsel) { (void)fsel; -#ifndef CODEC_SLAVE static const unsigned char srctrl_table[HW_NUM_FREQ] = { HW_HAVE_11_([HW_FREQ_11] = CODEC_SRCTRL_11025HZ,) @@ -292,10 +300,23 @@ void audiohw_set_frequency(int fsel) fsel = HW_FREQ_DEFAULT; wmcodec_write(CLOCKING, srctrl_table[fsel]); -#endif } #if defined(HAVE_WM8750) +#ifdef AUDIOHW_HAVE_DEPTH_3D +/* Set the depth of the 3D effect */ +void audiohw_set_depth_3d(int val) +{ + if (val) + wmcodec_write(ENHANCE_3D, + ENHANCE_3D_MODE3D_PLAYBACK | ENHANCE_3D_DEPTH(val) | + ENHANCE_3D_3DEN); + else + wmcodec_write(ENHANCE_3D,ENHANCE_3D_MODE3D_PLAYBACK); +} +#endif + +#ifdef HAVE_RECORDING void audiohw_set_recsrc(int source, bool recording) { /* INPUT1 - FM radio @@ -307,17 +328,30 @@ void audiohw_set_recsrc(int source, bool recording) * turn on output buffer(s) * * if recording == true we route input signal to PGA - * and monitoring picks up signal after PGA in analog domain + * and monitoring picks up signal after PGA and ADC * turn on ADC, PGA, DAC, output buffer(s) */ switch(source) { case AUDIO_SRC_PLAYBACK: - /* mute PGA, disable all audio paths but DAC and output stage*/ - wmcodec_write(LINVOL, LINVOL_LINMUTE | LINVOL_LINVOL(23)); /* 0dB */ - wmcodec_write(RINVOL, RINVOL_RINMUTE | RINVOL_RINVOL(23)); /* 0dB */ + /* turn off DAC and ADC in order to setup Enchance 3D function + * for playback. This does not turn on enchancement but + * the switch between playback/record has to be done with + * DAC and ADC off + */ +#ifdef AUDIOHW_HAVE_DEPTH_3D wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); + wmcodec_write(PWRMGMT2, 0x00); + wmcodec_write(ENHANCE_3D, ENHANCE_3D_MODE3D_PLAYBACK); +#endif + /* mute PGA, disable all audio paths but DAC and output stage*/ + wmcodec_write(LINVOL, LINVOL_LINMUTE | LINVOL_LINVOL(0x17)); /* 0dB */ + wmcodec_write(RINVOL, RINVOL_RINMUTE | RINVOL_RINVOL(0x17)); /* 0dB */ + + wmcodec_write(LOUT1, LOUT1_BITS); + wmcodec_write(ROUT1, ROUT1_BITS); + wmcodec_write(PWRMGMT2, PWRMGMT2_DACL | PWRMGMT2_DACR | PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1); @@ -332,15 +366,26 @@ void audiohw_set_recsrc(int source, bool recording) case AUDIO_SRC_FMRADIO: if(recording) { - /* Set input volume to PGA */ - wmcodec_write(LINVOL, LINVOL_LINVOL(23)); - wmcodec_write(RINVOL, RINVOL_RINVOL(23)); + /* turn off DAC and ADC in order to setup Enchance 3D function + * for playback. This does not turn on enchancement but + * the switch between playback/record has to be done with + * DAC and ADC off + */ +#ifdef AUDIOHW_HAVE_DEPTH_3D + wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); + wmcodec_write(PWRMGMT2, 0x00); + wmcodec_write(ENHANCE_3D, ENHANCE_3D_MODE3D_RECORD); +#endif /* Turn on PGA and ADC */ wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K | PWRMGMT1_AINL | PWRMGMT1_AINR | PWRMGMT1_ADCL | PWRMGMT1_ADCR); + /* Set input volume to PGA 0dB*/ + wmcodec_write(LINVOL, LINVOL_LIVU|LINVOL_LINVOL(0x17)); + wmcodec_write(RINVOL, RINVOL_RIVU|RINVOL_RINVOL(0x17)); + /* Setup input source for PGA as INPUT1 * MICBOOST disabled */ @@ -356,38 +401,45 @@ void audiohw_set_recsrc(int source, bool recording) wmcodec_write(PWRMGMT2, PWRMGMT2_DACL | PWRMGMT2_DACR | PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1); - /* analog monitor */ - wmcodec_write(LEFTMIX1, LEFTMIX1_LMIXSEL_ADCLIN | - LEFTMIX1_LD2LO); - wmcodec_write(RIGHTMIX2, RIGHTMIX2_RMIXSEL_ADCRIN | - RIGHTMIX2_RD2RO); + /* route DAC signal to output mixer */ + wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO); + wmcodec_write(RIGHTMIX2, RIGHTMIX2_RD2RO); } else { - /* turn off ADC, PGA */ wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); + wmcodec_write(LOUT1, LOUT1_BITS); + wmcodec_write(ROUT1, ROUT1_BITS); + /* turn on DAC and output stage */ wmcodec_write(PWRMGMT2, PWRMGMT2_DACL | PWRMGMT2_DACR | PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1); /* setup monitor mode by routing input signal to outmix - * at 0dB volume - */ + * at 0dB volume + */ wmcodec_write(LEFTMIX1, LEFTMIX1_LI2LO | LEFTMIX1_LMIXSEL_LINPUT1 | LEFTMIX1_LI2LOVOL(0x20) | LEFTMIX1_LD2LO); - wmcodec_write(RIGHTMIX2, RIGHTMIX2_RI2RO | RIGHTMIX2_RMIXSEL_RINPUT1 | + wmcodec_write(RIGHTMIX1, RIGHTMIX1_RMIXSEL_RINPUT1); + wmcodec_write(RIGHTMIX2, RIGHTMIX2_RI2RO | RIGHTMIX2_RI2ROVOL(0x20) | RIGHTMIX2_RD2RO); } break; case AUDIO_SRC_LINEIN: +#ifdef AUDIOHW_HAVE_DEPTH_3D + wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); + wmcodec_write(PWRMGMT2, 0x00); + wmcodec_write(ENHANCE_3D, ENHANCE_3D_MODE3D_RECORD); +#endif + /* Set input volume to PGA */ - wmcodec_write(LINVOL, LINVOL_LINVOL(23)); - wmcodec_write(RINVOL, RINVOL_RINVOL(23)); + wmcodec_write(LINVOL, LINVOL_LIVU | LINVOL_LINVOL(23)); + wmcodec_write(RINVOL, RINVOL_RIVU | RINVOL_RINVOL(23)); - /* Turn on PGA, ADC, DAC */ + /* Turn on PGA, ADC */ wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K | PWRMGMT1_AINL | PWRMGMT1_AINR | PWRMGMT1_ADCL | PWRMGMT1_ADCR); @@ -406,18 +458,21 @@ void audiohw_set_recsrc(int source, bool recording) * default is LADC -> LDATA, RADC -> RDATA * so we don't touch this */ - - /* digital monitor */ - wmcodec_write(LEFTMIX1, LEFTMIX1_LMIXSEL_ADCLIN | - LEFTMIX1_LD2LO); - wmcodec_write(RIGHTMIX2, RIGHTMIX2_RMIXSEL_ADCRIN | - RIGHTMIX2_RD2RO); + /* route DAC signal to output mixer */ + wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO); + wmcodec_write(RIGHTMIX2, RIGHTMIX2_RD2RO); break; case AUDIO_SRC_MIC: +#ifdef AUDIOHW_HAVE_DEPTH_3D + wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K); + wmcodec_write(PWRMGMT2, 0x00); + wmcodec_write(ENHANCE_3D, ENHANCE_3D_MODE3D_RECORD); +#endif + /* Set input volume to PGA */ - wmcodec_write(LINVOL, LINVOL_LINVOL(23)); - wmcodec_write(RINVOL, RINVOL_RINVOL(23)); + wmcodec_write(LINVOL, LINVOL_LIVU | LINVOL_LINVOL(23)); + wmcodec_write(RINVOL, RINVOL_RIVU | RINVOL_RINVOL(23)); /* Turn on PGA and ADC, turn off DAC */ wmcodec_write(PWRMGMT1, PWRMGMT1_VREF | PWRMGMT1_VMIDSEL_50K | @@ -439,21 +494,19 @@ void audiohw_set_recsrc(int source, bool recording) * so we don't touch this */ - /* analog monitor */ - wmcodec_write(LEFTMIX1, LEFTMIX1_LMIXSEL_ADCLIN | - LEFTMIX1_LD2LO); - wmcodec_write(RIGHTMIX2, RIGHTMIX2_RMIXSEL_ADCRIN | - RIGHTMIX2_RD2RO); - break; + /* route DAC signal to output mixer */ + wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO); + wmcodec_write(RIGHTMIX2, RIGHTMIX2_RD2RO); } /* switch(source) */ } /* Setup PGA gain */ -void audiohw_set_recvol(int left, int right, int type) +void audiohw_set_recvol(int vol_l, int vol_r, int type) { (void)type; - wmcodec_write(LINVOL, LINVOL_LINVOL(recvol2hw(left))); - wmcodec_write(RINVOL, RINVOL_RINVOL(recvol2hw(right))); + wmcodec_write(LINVOL, LINVOL_LIZC|LINVOL_LINVOL(recvol2hw(vol_l))); + wmcodec_write(RINVOL, RINVOL_RIZC|RINVOL_RIVU|RINVOL_RINVOL(recvol2hw(vol_r))); } -#endif +#endif /* HAVE_RECORDING */ +#endif /* HAVE_WM8750 */ diff --git a/firmware/export/config/mpiohd200.h b/firmware/export/config/mpiohd200.h index 465154a4bd..b9e9b11e2d 100644 --- a/firmware/export/config/mpiohd200.h +++ b/firmware/export/config/mpiohd200.h @@ -14,26 +14,18 @@ #define ATA_SWAP_WORDS /* define this if you have recording possibility */ -/* not implemented yet - * #define HAVE_RECORDING - */ - +#define HAVE_RECORDING /* Define bitmask of input sources - recordable bitmask can be defined * explicitly if different - * not implemented yet */ - #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO) - /* define the bitmask of hardware sample rates */ #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) -/* define the bitmask of recording sample rates - * not implemented yet - *#define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) - */ +/* define the bitmask of recording sample rates */ +#define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) /* define this if you have a bitmap LCD display */ #define HAVE_LCD_BITMAP @@ -114,9 +106,17 @@ #define CONFIG_TUNER_XTAL 32768 -/* we have WM8750 codec in I2S slave mode */ +/* we have WM8750 codec in I2S master mode */ #define HAVE_WM8750 -#define CODEC_SLAVE + +/* clocking setup based on 11.2896 MHz master clock + * provided to the codec by MCU + * WM8750L Datasheet Table 40, page 46 + */ +#define CODEC_SRCTRL_11025HZ (0x18 << 1) +#define CODEC_SRCTRL_22050HZ (0x1A << 1) +#define CODEC_SRCTRL_44100HZ (0x10 << 1) +#define CODEC_SRCTRL_88200HZ (0x1E << 1) #define BATTERY_CAPACITY_DEFAULT 950 /* default battery capacity */ #define BATTERY_CAPACITY_MIN 950 /* min. capacity selectable */ @@ -142,12 +142,6 @@ /* Define this if you want to use coldfire's i2c interface */ #define CONFIG_I2C I2C_COLDFIRE -/* OF resets device instead of poweroff while charging - * this triggers bootloader code which takes care of charging. - * I have feeling that powering off while charging may cause - * partition table corruption I am experiencing from time to time - */ - /* define this if the hardware can be powered off while charging */ /* #define HAVE_POWEROFF_WHILE_CHARGING */ diff --git a/firmware/export/wm8751.h b/firmware/export/wm8751.h index 8992c88076..7a3a3075af 100644 --- a/firmware/export/wm8751.h +++ b/firmware/export/wm8751.h @@ -25,13 +25,19 @@ #define VOLUME_MIN -730 #define VOLUME_MAX 60 +/* turn off 3D Enchance feature of WM8750 for now +#if defined(HAVE_WM8750) +#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | PRESCALER_CAP | DEPTH_3D_CAP) +#else +*/ #define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP | PRESCALER_CAP) +/* #endif */ extern int tenthdb2master(int db); extern void audiohw_set_master_vol(int vol_l, int vol_r); extern void audiohw_set_lineout_vol(int vol_l, int vol_r); -#if defined(HAVE_WM8750) +#if defined(HAVE_WM8750) && defined(HAVE_RECORDING) void audiohw_set_recsrc(int source, bool recording); #endif @@ -222,7 +228,7 @@ void audiohw_set_recsrc(int source, bool recording); #define ADCL_LMICBOOST_13DB (1 << 4) #define ADCL_LMICBOOST_20DB (2 << 4) #define ADCL_LMICBOOST_29DB (3 << 4) -#define ADCL_LMICBOOST(x) ((x) & (0x3 << 7)) +#define ADCL_LMICBOOST(x) (((x) & 0x3) << 4)) #define ADCL_LINSEL_LINPUT1 (0 << 6) #define ADCL_LINSEL_LINPUT2 (1 << 6) #define ADCL_LINSEL_LINPUT3 (2 << 6) diff --git a/firmware/target/coldfire/mpio/audio-mpio.c b/firmware/target/coldfire/mpio/audio-mpio.c index 217881547e..88c43383ca 100644 --- a/firmware/target/coldfire/mpio/audio-mpio.c +++ b/firmware/target/coldfire/mpio/audio-mpio.c @@ -46,6 +46,7 @@ void audio_set_output_source(int source) if ((unsigned)source >= AUDIO_NUM_SOURCES) source = AUDIO_SRC_PLAYBACK; + /* route incoming audio samples to DAC */ IIS2CONFIG = (IIS2CONFIG & ~(7 << 8)) | (txsrc_select[source+1] << 8); restore_irq(level); @@ -73,8 +74,8 @@ void audio_input_mux(int source, unsigned flags) break; case AUDIO_SRC_MIC: - case AUDIO_SRC_LINEIN: - /* recording only */ + case AUDIO_SRC_LINEIN: + /* recording only */ if (source != last_source) { audiohw_set_recsrc(source,true); @@ -89,10 +90,10 @@ void audio_input_mux(int source, unsigned flags) last_recording = recording; + audiohw_set_recsrc(source,recording); /* Int. when 6 samples in FIFO, PDIR2 src = iis1RcvData */ coldfire_set_dataincontrol(recording ? ((3 << 14) | (4 << 3)) : 0); - audiohw_set_recsrc(source, recording); break; } diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c index 06f17d1170..fa320dff3f 100644 --- a/firmware/target/coldfire/pcm-coldfire.c +++ b/firmware/target/coldfire/pcm-coldfire.c @@ -84,13 +84,18 @@ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = #endif #if CONFIG_CPU == MCF5249 && defined(HAVE_WM8750) +/* We run codec in master mode. + * Codec can reconstruct all frequencies + * from single 11.2896 MHz master clock + */ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = { - [HW_FREQ_88] = { 0x0c, 0x01 }, - [HW_FREQ_44] = { 0x06, 0x01 }, - [HW_FREQ_22] = { 0x04, 0x01 }, - [HW_FREQ_11] = { 0x02, 0x01 }, + [HW_FREQ_88] = { 0x00, 0x01 }, + [HW_FREQ_44] = { 0x00, 0x01 }, + [HW_FREQ_22] = { 0x00, 0x01 }, + [HW_FREQ_11] = { 0x00, 0x01 }, }; + #endif #if (CONFIG_CPU == MCF5250 || CONFIG_CPU == MCF5249) && defined(HAVE_TLV320) -- 2.11.4.GIT