From c495cdae5926c9245d7c943c72a97206d4a0e22a Mon Sep 17 00:00:00 2001 From: Barry Wardell Date: Sun, 11 Nov 2007 16:00:33 +0000 Subject: FS#8046: H10 FM tuner support. Thanks to Przemyslaw Holubowski for doing the hard work in figuring out how to communicate with the tuner. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15578 a1c6a512-1295-4272-9138-f99709370657 --- apps/keymaps/keymap-h10.c | 23 ++- apps/recorder/radio.c | 4 + firmware/SOURCES | 2 + firmware/drivers/audio/wm8731.c | 13 +- firmware/export/config-h10.h | 6 +- firmware/export/config-h10_5gb.h | 6 +- firmware/target/arm/audio-pp.c | 16 +- firmware/target/arm/iriver/h10/fmradio_i2c-h10.c | 206 +++++++++++++++++++++++ firmware/target/arm/iriver/h10/power-h10.c | 2 - 9 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 firmware/target/arm/iriver/h10/fmradio_i2c-h10.c diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c index 3e90f1520e..883b0d37d4 100644 --- a/apps/keymaps/keymap-h10.c +++ b/apps/keymaps/keymap-h10.c @@ -305,6 +305,26 @@ const struct button_mapping button_context_recscreen[] = { LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) }; /* button_context_recscreen */ +static const struct button_mapping button_context_radio[] = { + { ACTION_FM_PRESET, BUTTON_RIGHT | BUTTON_REL, BUTTON_RIGHT }, + { ACTION_FM_MENU, BUTTON_RIGHT | BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_FM_MODE, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_FM_STOP, BUTTON_PLAY | BUTTON_REPEAT, BUTTON_PLAY }, + { ACTION_FM_EXIT, BUTTON_POWER, BUTTON_NONE }, + { ACTION_FM_PLAY, BUTTON_PLAY | BUTTON_REL, BUTTON_PLAY }, + { ACTION_SETTINGS_INC, BUTTON_SCROLL_UP, BUTTON_NONE }, + { ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_DEC, BUTTON_SCROLL_DOWN, BUTTON_NONE }, + { ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_REW, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_FF, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_FF|BUTTON_REPEAT, BUTTON_NONE }, + + LAST_ITEM_IN_LIST + +}; + static const struct button_mapping* get_context_mapping_remote( int context ) { context ^= CONTEXT_REMOTE; @@ -385,7 +405,8 @@ const struct button_mapping* get_context_mapping(int context) return button_context_keyboard; case CONTEXT_RECSCREEN: return button_context_recscreen; - + case CONTEXT_FM: + return button_context_radio; default: return button_context_standard; } diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index a0cc10ce18..7a45027933 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c @@ -81,6 +81,10 @@ #define FM_NEXT_PRESET #define FM_PREV_PRESET +#elif CONFIG_KEYPAD == IRIVER_H10_PAD +#define FM_PRESET +#define FM_MODE + #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) #define FM_PRESET #define FM_MODE diff --git a/firmware/SOURCES b/firmware/SOURCES index e78d74a198..465d10e662 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -557,6 +557,7 @@ target/arm/i2s-pp.c target/arm/iriver/h10/adc-h10.c target/arm/iriver/h10/backlight-h10.c target/arm/iriver/h10/button-h10.c +target/arm/iriver/h10/fmradio_i2c-h10.c target/arm/iriver/h10/lcd-h10_20gb.c target/arm/iriver/h10/power-h10.c target/arm/iriver/h10/powermgmt-h10.c @@ -573,6 +574,7 @@ target/arm/i2s-pp.c target/arm/iriver/h10/adc-h10.c target/arm/iriver/h10/backlight-h10.c target/arm/iriver/h10/button-h10.c +target/arm/iriver/h10/fmradio_i2c-h10.c target/arm/iriver/h10/lcd-h10_5gb.c target/arm/iriver/h10/power-h10.c target/arm/iriver/h10/powermgmt-h10.c diff --git a/firmware/drivers/audio/wm8731.c b/firmware/drivers/audio/wm8731.c index 785cb2a91c..44aeefe791 100644 --- a/firmware/drivers/audio/wm8731.c +++ b/firmware/drivers/audio/wm8731.c @@ -319,6 +319,15 @@ void audiohw_set_recvol(int left, int right, int type) void audiohw_set_monitor(int enable) { - /* TODO: Implement for FM monitoring */ - (void)enable; + if(enable) + { + wm8731_regs[AAPCTRL] |= AAPCTRL_BYPASS; + wm8731_regs[AAPCTRL] &=~ (AAPCTRL_DACSEL | AAPCTRL_SIDETONE); + wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); + } + else { + wm8731_regs[AAPCTRL] &=~ AAPCTRL_BYPASS; + wm8731_regs[AAPCTRL] |= AAPCTRL_DACSEL | AAPCTRL_SIDETONE; + wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); + } } diff --git a/firmware/export/config-h10.h b/firmware/export/config-h10.h index 039ebc588f..e1e0b54e28 100644 --- a/firmware/export/config-h10.h +++ b/firmware/export/config-h10.h @@ -12,7 +12,7 @@ #define HAVE_RECORDING /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ -#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) +#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_44) @@ -88,8 +88,8 @@ #define AB_REPEAT_ENABLE 1 /* FM Tuner */ -/*#define CONFIG_TUNER TEA5767 -#define CONFIG_TUNER_XTAL 32768 *//* TODO: what is this? */ +#define CONFIG_TUNER TEA5767 +#define CONFIG_TUNER_XTAL 32768 /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT diff --git a/firmware/export/config-h10_5gb.h b/firmware/export/config-h10_5gb.h index 3d10af26cf..b7195221ca 100644 --- a/firmware/export/config-h10_5gb.h +++ b/firmware/export/config-h10_5gb.h @@ -12,7 +12,7 @@ #define HAVE_RECORDING /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ -#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) +#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_44) @@ -74,8 +74,8 @@ #define AB_REPEAT_ENABLE 1 /* FM Tuner */ -/*#define CONFIG_TUNER TEA5767 -#define CONFIG_TUNER_XTAL 32768 *//* TODO: what is this? */ +#define CONFIG_TUNER TEA5767 +#define CONFIG_TUNER_XTAL 32768 /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT diff --git a/firmware/target/arm/audio-pp.c b/firmware/target/arm/audio-pp.c index 9fff197520..783342ef37 100644 --- a/firmware/target/arm/audio-pp.c +++ b/firmware/target/arm/audio-pp.c @@ -35,6 +35,7 @@ void audio_input_mux(int source, unsigned flags) /* Prevent pops from unneeded switching */ static int last_source = AUDIO_SRC_PLAYBACK; #ifdef HAVE_FMRADIO_REC + bool recording = flags & SRCF_RECORDING; static bool last_recording = false; #endif @@ -62,6 +63,10 @@ void audio_input_mux(int source, unsigned flags) #endif #ifdef HAVE_LINEIN_REC case AUDIO_SRC_LINEIN: /* recording only */ +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* Switch line in source to line-in */ + GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x04); +#endif if (source != last_source) { audiohw_enable_recording(false); /* source line */ @@ -71,17 +76,20 @@ void audio_input_mux(int source, unsigned flags) #endif #ifdef HAVE_FMRADIO_REC case AUDIO_SRC_FMRADIO: /* recording and playback */ +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* Switch line in source to tuner */ + GPIO_CLEAR_BITWISE(GPIOB_OUTPUT_VAL, 0x04); +#endif /* Set line-in vol to 0dB*/ if (!recording) - audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN); + audiohw_set_recvol(0x17, 0x17, AUDIO_GAIN_LINEIN); if (source == last_source && recording == last_recording) break; last_recording = recording; - /* I2S recording and playback */ - audiohw_enable_recording(false); /* source line */ - audiohw_set_monitor(!recording); + audiohw_enable_recording(false); /* select line-in source */ + audiohw_set_monitor(!recording); /* enable bypass mode */ break; #endif } /* end switch */ diff --git a/firmware/target/arm/iriver/h10/fmradio_i2c-h10.c b/firmware/target/arm/iriver/h10/fmradio_i2c-h10.c new file mode 100644 index 0000000000..f3d3075df9 --- /dev/null +++ b/firmware/target/arm/iriver/h10/fmradio_i2c-h10.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Physical interface of the Philips TEA5767 in iriver H10 series + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * 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 "cpu.h" +#include "logf.h" +#include "system.h" + +/* cute little functions, atomic read-modify-write */ + +#define SDA_OUTINIT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x08) +#define SDA_HI_IN GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x08) +#define SDA_LO_OUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x08) +#define SDA (GPIOD_INPUT_VAL & 0x08) + +#define SCL_INPUT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x10) +#define SCL_OUTPUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x10) +#define SCL_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x10) +#define SCL_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL,0x10) +#define SCL (GPIOD_INPUT_VAL & 0x10) + +#define DELAY udelay(2) + +static void fmradio_i2c_start(void) +{ + SCL_HI; + SCL_OUTPUT; + SDA_HI_IN; + SDA_OUTINIT; + DELAY; + SDA_LO_OUT; + DELAY; + SCL_LO; +} + +static void fmradio_i2c_stop(void) +{ + SDA_LO_OUT; + DELAY; + SCL_HI; + DELAY; + SDA_HI_IN; +} + +/* Generate ACK or NACK */ +static void fmradio_i2c_ack(bool nack) +{ + /* Here's the deal. The slave is slow, and sometimes needs to wait + before it can receive the acknowledge. Therefore it forces the clock + low until it is ready. We need to poll the clock line until it goes + high before we release the ack. + + In their infinite wisdom, iriver didn't pull up the SCL line, so + we have to drive the SCL high repeatedly to simulate a pullup. */ + + if (nack) + SDA_HI_IN; + else + SDA_LO_OUT; + DELAY; + + SCL_HI; + do + { + SCL_OUTPUT; /* Set the clock to output */ + SCL_INPUT; /* Set the clock to input */ + DELAY; + } + while(!SCL); /* and wait for the slave to release it */ + + SCL_OUTPUT; + SCL_LO; +} + +static int fmradio_i2c_getack(void) +{ + int ret = 1; + + /* Here's the deal. The slave is slow, and sometimes needs to wait + before it can send the acknowledge. Therefore it forces the clock + low until it is ready. We need to poll the clock line until it goes + high before we read the ack. + + In their infinite wisdom, iriver didn't pull up the SCL line, so + we have to drive the SCL high repeatedly to simulate a pullup. */ + + SDA_HI_IN; + DELAY; + + SCL_HI; /* set clock to high */ + do + { + SCL_OUTPUT; /* Set the clock to output */ + SCL_INPUT; /* Set the clock to input */ + DELAY; + } + while(!SCL); /* and wait for the slave to release it */ + + if (SDA) + ret = 0; /* ack failed */ + + SCL_OUTPUT; + SCL_LO; + + return ret; +} + +static void fmradio_i2c_outb(unsigned char byte) +{ + int i; + + /* clock out each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) { + if ( i & byte ) + SDA_HI_IN; + else + SDA_LO_OUT; + DELAY; + SCL_HI; + DELAY; + SCL_LO; + } +} + +static unsigned char fmradio_i2c_inb(void) +{ + int i; + unsigned char byte = 0; + + SDA_HI_IN; + /* clock in each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) { + DELAY; + SCL_HI; + DELAY; + if ( SDA ) + byte |= i; + SCL_LO; + } + + return byte; +} + +int fmradio_i2c_write(int address, const unsigned char* buf, int count) +{ + int i,x=0; + + fmradio_i2c_start(); + fmradio_i2c_outb(address & 0xfe); + if (fmradio_i2c_getack()) + { + for (i=0; i0; i--) + { + *buf++ = fmradio_i2c_inb(); + fmradio_i2c_ack(i == 1); + } + } + else + x=-1; + fmradio_i2c_stop(); + return x; +} diff --git a/firmware/target/arm/iriver/h10/power-h10.c b/firmware/target/arm/iriver/h10/power-h10.c index 7f3fb40b36..f4d5be49a6 100644 --- a/firmware/target/arm/iriver/h10/power-h10.c +++ b/firmware/target/arm/iriver/h10/power-h10.c @@ -35,7 +35,6 @@ bool charger_enabled; #endif -#if 0 #if CONFIG_TUNER bool tuner_power(bool status) @@ -46,7 +45,6 @@ bool tuner_power(bool status) } #endif /* #if CONFIG_TUNER */ -#endif void power_init(void) { -- cgit v1.2.3