diff --git a/apps/keymaps/keymap-yh8xx_yh9xx.c b/apps/keymaps/keymap-yh8xx_yh9xx.c index 7125134d8c..03f6f8bcff 100644 --- a/apps/keymaps/keymap-yh8xx_yh9xx.c +++ b/apps/keymaps/keymap-yh8xx_yh9xx.c @@ -296,6 +296,27 @@ static const struct button_mapping button_context_keyboard[] = { LAST_ITEM_IN_LIST }; /* button_context_keyboard */ +#if CONFIG_TUNER +static const struct button_mapping button_context_radio[] = { + { ACTION_FM_MENU, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT }, + { ACTION_FM_EXIT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_FM_PLAY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY }, + { ACTION_FM_STOP, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_FM_PRESET, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT}, + { ACTION_FM_MODE, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE }, + { ACTION_SETTINGS_INCREPEAT,BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE }, + { ACTION_SETTINGS_DECREPEAT,BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_FFWD, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_FFWD|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_REW, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE }, + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) +}; /* button_context_radio */ +#endif + const struct button_mapping* get_context_mapping(int context) { switch (context) @@ -342,6 +363,10 @@ const struct button_mapping* get_context_mapping(int context) return button_context_recscreen; case CONTEXT_KEYBOARD: return button_context_keyboard; - } +#if CONFIG_TUNER + case CONTEXT_FM: + return button_context_radio; +#endif + } return button_context_standard; } diff --git a/apps/radio/radio.c b/apps/radio/radio.c index fdbcc89641..0365b6aafa 100644 --- a/apps/radio/radio.c +++ b/apps/radio/radio.c @@ -91,7 +91,8 @@ #define FM_RECORD #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) ||\ - (CONFIG_KEYPAD == SANSA_FUZE_PAD) || (CONFIG_KEYPAD == SANSA_CLIP_PAD) + (CONFIG_KEYPAD == SANSA_FUZE_PAD) || (CONFIG_KEYPAD == SANSA_CLIP_PAD) ||\ + (CONFIG_KEYPAD == SAMSUNG_YH920_PAD) #define FM_MENU #define FM_PRESET #define FM_STOP diff --git a/firmware/SOURCES b/firmware/SOURCES index 374210e30b..ef71a2b048 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1705,6 +1705,7 @@ target/arm/samsung/yh920/backlight-yh920.c target/arm/samsung/yh920/lcd-yh920.c target/arm/samsung/yh920/lcd-as-yh920.S target/arm/samsung/yh920/powermgmt-yh920.c +target/arm/samsung/fmradio-yh92x.c #endif /* SAMSUNG_YH920 */ #ifdef SAMSUNG_YH925 diff --git a/firmware/drivers/audio/ak4537.c b/firmware/drivers/audio/ak4537.c index bea3dc7019..a42b1346d2 100644 --- a/firmware/drivers/audio/ak4537.c +++ b/firmware/drivers/audio/ak4537.c @@ -221,34 +221,64 @@ void audiohw_set_frequency(int fsel) } #if defined(HAVE_RECORDING) -void audiohw_enable_recording(bool source_mic) +void audiohw_set_recsrc(int source) { - if (source_mic) + switch(source) { - /* enable mic power supply */ + case AUDIO_SRC_PLAYBACK: + /* disable mic power supply */ #if defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) - /* additionally select external mic */ - akc_set(AK4537_MIC, MPWRE | MSEL); + akc_clear(AK4537_MIC, MPWRE); #else - akc_set(AK4537_MIC, MPWRI); + akc_clear(AK4537_MIC, MPWRI); #endif + /* power down ADC, mic preamp and line amp */ + akc_clear(AK4537_PM1, PMADL | PMMICL | PMIPGL); + akc_clear(AK4537_PM3, PMADR | PMMICR | PMIPGR); - /* mic out is connected to line1 input */ - akc_clear(AK4537_PM3, INL | INR); + /* break ADC -> DAC connection */ + akc_clear(AK4537_MODE2, LOOP); + break; + +#if (INPUT_SRC_CAPS & SRC_CAP_FMRADIO) + case AUDIO_SRC_FMRADIO: + /* disable mic power supply */ +#if defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) + akc_clear(AK4537_MIC, MPWRE); +#else + akc_clear(AK4537_MIC, MPWRI); +#endif + /* disable mic preamp */ + akc_clear(AK4537_PM1, PMMICL); + + /* Select line2 input: Radio */ + akc_set(AK4537_PM3, INL | INR); /* route ALC output to ADC input */ akc_set(AK4537_MIC, MICAD); /* set ALC (automatic level control) to manual mode */ akc_clear(AK4537_ALC1, ALC1); - /* set gain control to 'dependent' (left&right at the same time) */ - akc_clear(AK4537_MIC, IPGAC); - /* power up mic preamp, left channel ADC and line in */ - akc_set(AK4537_PM1, PMMICL | PMIPGL | PMADL); - /* power up right channel ADC and line in */ + + /* set gain control to independent left & right gain */ + akc_set(AK4537_MIC, IPGAC); + + /* power up left channel input and ADC */ + akc_set(AK4537_PM1, PMADL | PMIPGL); + /* power up right channel input and ADC */ akc_set(AK4537_PM3, PMADR | PMIPGR); - } - else - { + + /* set line in vol = 0 dB */ + akc_write(AK4537_IPGAL, 0x2f); + akc_write(AK4537_IPGAR, 0x2f); + + /* ADC -> DAC, external data to DAC ignored */ + akc_set(AK4537_MODE2, LOOP); + + break; +#endif /* INPUT_SRC_CAPS & SRC_CAP_FMRADIO */ + +#if (INPUT_SRC_CAPS & SRC_CAP_LINEIN) + case AUDIO_SRC_LINEIN: /* disable mic power supply */ #if defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) akc_clear(AK4537_MIC, MPWRE); @@ -272,25 +302,44 @@ void audiohw_enable_recording(bool source_mic) akc_set(AK4537_PM1, PMADL | PMIPGL); /* power up right channel input and ADC */ akc_set(AK4537_PM3, PMADR | PMIPGR); - } - /* ADC -> DAC, external data to DAC ignored */ - akc_set(AK4537_MODE2, LOOP); -} -void audiohw_disable_recording(void) -{ - /* disable mic power supply */ + /* ADC -> DAC, external data to DAC ignored */ + akc_set(AK4537_MODE2, LOOP); + + break; +#endif /* INPUT_SRC_CAPS & SRC_CAP_LINEIN */ + +#if (INPUT_SRC_CAPS & SRC_CAP_MIC) + case AUDIO_SRC_MIC: + /* enable mic power supply */ #if defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) - akc_clear(AK4537_MIC, MPWRE); + /* additionally select external mic */ + akc_set(AK4537_MIC, MPWRE | MSEL); #else - akc_clear(AK4537_MIC, MPWRI); + akc_set(AK4537_MIC, MPWRI); #endif - /* power down ADC, mic preamp and line amp */ - akc_clear(AK4537_PM1, PMADL | PMMICL | PMIPGL); - akc_clear(AK4537_PM3, PMADR | PMMICR | PMIPGR); - /* break ADC -> DAC connection */ - akc_clear(AK4537_MODE2, LOOP); + /* mic out is connected to line1 input */ + akc_clear(AK4537_PM3, INL | INR); + + /* route ALC output to ADC input */ + akc_set(AK4537_MIC, MICAD); + /* set ALC (automatic level control) to manual mode */ + akc_clear(AK4537_ALC1, ALC1); + /* set gain control to 'dependent' (left&right at the same time) */ + akc_clear(AK4537_MIC, IPGAC); + /* power up mic preamp, left channel ADC and line in */ + akc_set(AK4537_PM1, PMMICL | PMIPGL | PMADL); + /* power up right channel ADC and line in */ + akc_set(AK4537_PM3, PMADR | PMIPGR); + + /* ADC -> DAC, external data to DAC ignored */ + akc_set(AK4537_MODE2, LOOP); + + break; +#endif /* INPUT_SRC_CAPS & SRC_CAP_MIC) */ + + } /* switch(source) */ } void audiohw_set_recvol(int left, int right, int type) @@ -331,9 +380,4 @@ void audiohw_set_recvol(int left, int right, int type) return; } } - -void audiohw_set_monitor(bool enable) -{ - (void)enable; -} #endif /* HAVE_RECORDING */ diff --git a/firmware/drivers/tuner/tea5767.c b/firmware/drivers/tuner/tea5767.c index d0041f9ce1..74adb54997 100644 --- a/firmware/drivers/tuner/tea5767.c +++ b/firmware/drivers/tuner/tea5767.c @@ -27,7 +27,9 @@ #include "power.h" #include "tuner.h" /* tuner abstraction interface */ #include "fmradio.h" -#include "fmradio_i2c.h" /* physical interface driver */ +#include "fmradio_i2c.h" /* physical interface driver - i2c */ +#include "fmradio_3wire.h" /* physical interface driver - 3-wire bus */ + #if defined(PHILIPS_HDD1630) || defined(ONDA_VX747) || defined(ONDA_VX777) || defined(PHILIPS_HDD6330) #define I2C_ADR 0x60 @@ -109,7 +111,11 @@ int tea5767_set(int setting, int value) if(setting == RADIO_SLEEP && !value) tuner_power(true); /* wakeup */ +#if defined(CONFIG_TUNER_3WIRE) + fmradio_3wire_write(write_bytes); +#else fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); +#endif if(setting == RADIO_SLEEP && value) tuner_power(false); /* sleep */ return 1; @@ -121,7 +127,11 @@ int tea5767_get(int setting) unsigned char read_bytes[5]; int val = -1; /* default for unsupported query */ +#if defined(CONFIG_TUNER_3WIRE) + fmradio_3wire_read(read_bytes); +#else fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes)); +#endif switch(setting) { @@ -141,7 +151,7 @@ int tea5767_get(int setting) case RADIO_STEREO: val = read_bytes[2] >> 7; break; - + case RADIO_RSSI: val = 10 + 3*(read_bytes[3] >> 4); break; @@ -161,15 +171,22 @@ int tea5767_get(int setting) void tea5767_init(void) { /* save binsize by only detecting presence for targets where it may be absent */ -#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) +#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || defined(SAMSUNG_YH920) unsigned char buf[5]; unsigned char chipid; /* init chipid register with 0xFF in case fmradio_i2c_read fails silently */ buf[3] = 0xFF; tuner_power(true); - if (fmradio_i2c_read(I2C_ADR, buf, sizeof(buf)) < 0) { - /* no i2c device detected */ + +#if defined(CONFIG_TUNER_3WIRE) + int res = fmradio_3wire_read(buf); +#else + int res = fmradio_i2c_read(I2C_ADR, buf, sizeof(buf)); +#endif + + if (res < 0) { + /* no device detected on bus */ tuner_present = false; } else { /* check chip id */ @@ -182,6 +199,10 @@ void tea5767_init(void) void tea5767_dbg_info(struct tea5767_dbg_info *info) { +#if defined(CONFIG_TUNER_3WIRE) + fmradio_3wire_read(info->read_regs); +#else fmradio_i2c_read(I2C_ADR, info->read_regs, 5); +#endif memcpy(info->write_regs, write_bytes, 5); } diff --git a/firmware/export/ak4537.h b/firmware/export/ak4537.h index 1c09b5aa2f..0ab0ca1594 100644 --- a/firmware/export/ak4537.h +++ b/firmware/export/ak4537.h @@ -34,6 +34,8 @@ AUDIOHW_SETTING(RIGHT_GAIN, "dB", 0, 1, -23, 12, 0) /* mic gain: +15dB fixed +20dB switchable mic preamp gain and the line stage of -23..+12dB make a total range of -8..+47dB */ AUDIOHW_SETTING(MIC_GAIN, "dB", 0, 1, -8, 47, 20) + +void audiohw_set_recsrc(int source); #endif /* HAVE_RECORDING */ #define AKC_NUM_REGS 0x11 diff --git a/firmware/export/config/samsungyh920.h b/firmware/export/config/samsungyh920.h index 7d6d590d96..d40a065e00 100644 --- a/firmware/export/config/samsungyh920.h +++ b/firmware/export/config/samsungyh920.h @@ -11,7 +11,7 @@ /* 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_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ @@ -133,6 +133,12 @@ /* AK4537 has no tone controls, so we use the software ones */ #define HAVE_SW_TONE_CONTROLS +/* FM Tuner */ +#define CONFIG_TUNER TEA5767 +#define CONFIG_TUNER_XTAL 32768 +/* Define this if the tuner uses 3-wire bus instead of classic i2c */ +#define CONFIG_TUNER_3WIRE + #define AB_REPEAT_ENABLE #define BATTERY_CAPACITY_DEFAULT 1550 /* default battery capacity */ diff --git a/firmware/export/fmradio_3wire.h b/firmware/export/fmradio_3wire.h new file mode 100644 index 0000000000..cafce9c8ec --- /dev/null +++ b/firmware/export/fmradio_3wire.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Physical interface of the Philips TEA5767 + * + * Copyright (C) 2014 by Szymon Dziok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef FMRADIO_TRIWIRE_H +#define FMRADIO_TRIWIRE_H + +#include "config.h" /* for INIT_ATTR */ +#include + +void fmradio_3wire_init(void) INIT_ATTR; +void fmradio_3wire_enable(bool enable); +int fmradio_3wire_write(const unsigned char* buf); +int fmradio_3wire_read(unsigned char* buf); + +#endif diff --git a/firmware/target/arm/pp/audio-pp.c b/firmware/target/arm/pp/audio-pp.c index 6b5b082cc7..76740f2e42 100644 --- a/firmware/target/arm/pp/audio-pp.c +++ b/firmware/target/arm/pp/audio-pp.c @@ -30,6 +30,25 @@ void audio_set_output_source(int source) source = AUDIO_SRC_PLAYBACK; } /* audio_set_output_source */ +#ifdef HAVE_AK4537 +void audio_input_mux(int source, unsigned flags) +{ + (void)flags; + /* Prevent pops from unneeded switching */ + static int last_source = AUDIO_SRC_PLAYBACK; + +#ifdef HAVE_FMRADIO_REC + bool recording = flags & SRCF_RECORDING; + + if ((source == AUDIO_SRC_FMRADIO) && (!recording)) + audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN); /* Set line-in vol to 0dB*/ +#endif + if (source != last_source) + audiohw_set_recsrc(source); + + last_source = source; +} +#else void audio_input_mux(int source, unsigned flags) { (void)flags; @@ -132,4 +151,6 @@ void audio_input_mux(int source, unsigned flags) last_source = source; } /* audio_input_mux */ +#endif + #endif /* INPUT_SRC_CAPS != 0 */ diff --git a/firmware/target/arm/samsung/fmradio-yh92x.c b/firmware/target/arm/samsung/fmradio-yh92x.c new file mode 100644 index 0000000000..4637aca287 --- /dev/null +++ b/firmware/target/arm/samsung/fmradio-yh92x.c @@ -0,0 +1,120 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Physical interface of the Philips TEA5767 in Samsung YH-92x + * + * Copyright (C) 2014 by Szymon Dziok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "cpu.h" +#include "fmradio_3wire.h" + +#define CLOCK_EN GPIO_SET_BITWISE(GPIOL_ENABLE, 0x10) +#define CLOCK_OUT GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x10) +#define CLOCK_LO GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x10) +#define CLOCK_HI GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x10) + +#define DATA (GPIOL_INPUT_VAL & 0x08) +#define DATA_EN GPIO_SET_BITWISE(GPIOL_ENABLE, 0x08) +#define DATA_IN GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_EN, 0x08) +#define DATA_OUT GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x08) +#define DATA_LO GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x08) +#define DATA_HI GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x08) + +#define READWRITE_EN GPIO_SET_BITWISE(GPIOL_ENABLE, 0x01) +#define READWRITE_OUT GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x01) +#define READWRITE_LO GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x01) +#define READWRITE_HI GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x01) + +#define DELAY1 udelay(1) +#define DELAY2 udelay(2) + +void fmradio_3wire_init(void) +{ + READWRITE_EN; + READWRITE_OUT; + + DATA_EN; + DATA_IN; + + CLOCK_EN; + CLOCK_HI; + CLOCK_OUT; + + DELAY2; +} + +int fmradio_3wire_write(const unsigned char* buf) +{ + int i, j; + + CLOCK_LO; + READWRITE_LO; + DELAY2; + READWRITE_HI; + DELAY1; + DATA_OUT; + + /* 5 bytes to the tuner */ + for (j = 0; j < 5; j++) + { + for (i = 7; i >= 0; i--) + { + if ((buf[j] >> i) & 0x1) DATA_HI; + else DATA_LO; + DELAY1; + CLOCK_HI; + DELAY2; + CLOCK_LO; + DELAY1; + } + } + READWRITE_LO; + + return j; +} + +int fmradio_3wire_read(unsigned char* buf) +{ + int i, j; + + CLOCK_LO; + READWRITE_HI; + DELAY2; + READWRITE_LO; + DELAY2; + DATA_IN; + + /* 5 bytes from the tuner */ + for (j = 0; j < 5; j++) + { + buf[j] = 0; + for (i = 7; i >= 0; i--) + { + buf[j] |= ((DATA >> 3) << i); + + CLOCK_HI; + DELAY2; + CLOCK_LO; + DELAY2; + } + } + READWRITE_HI; + + return j; +} diff --git a/firmware/target/arm/samsung/power-yh82x_yh92x.c b/firmware/target/arm/samsung/power-yh82x_yh92x.c index 021ddade4d..b6c18c5fd0 100644 --- a/firmware/target/arm/samsung/power-yh82x_yh92x.c +++ b/firmware/target/arm/samsung/power-yh82x_yh92x.c @@ -20,7 +20,7 @@ ****************************************************************************/ /* Created from power.c using some iPod code, and some custom stuff based on - GPIO analysis + GPIO analysis */ #include "config.h" @@ -32,9 +32,26 @@ #include "power.h" #include "logf.h" #include "usb.h" +#include "fmradio_3wire.h" + +#if CONFIG_TUNER +bool tuner_power(bool status) +{ + GPIO_SET_BITWISE(GPIOL_ENABLE, 0x04); + GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x04); + if (status) + GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x04); + else + GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x04); + return status; +} +#endif void power_init(void) { +#if CONFIG_TUNER + fmradio_3wire_init(); +#endif } unsigned int power_input_status(void)