Index: apps/recorder/radio.c =================================================================== --- apps/recorder/radio.c (revision 13475) +++ apps/recorder/radio.c (working copy) @@ -73,6 +73,14 @@ #define FM_PRESET #define FM_MODE +#elif (CONFIG_KEYPAD == SANSA_E200_PAD) +#define FM_MENU +#define FM_PRESET +#define FM_STOP +#define FM_MODE +#define FM_EXIT +#define FM_PLAY + #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) #define FM_PRESET #define FM_MODE @@ -485,7 +493,7 @@ #endif /* ndef SIMULATOR */ /* turn on radio */ -#if CONFIG_CODEC == SWCODEC +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) rec_set_source(AUDIO_SRC_FMRADIO, (radio_status == FMRADIO_PAUSED) ? SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING); @@ -656,7 +664,11 @@ case ACTION_SETTINGS_INC: case ACTION_SETTINGS_INCREPEAT: +#ifdef SANSA_E200 + global_settings.volume--; +#else global_settings.volume++; +#endif if(global_settings.volume > sound_max(SOUND_VOLUME)) global_settings.volume = sound_max(SOUND_VOLUME); sound_set_volume(global_settings.volume); @@ -666,7 +678,11 @@ case ACTION_SETTINGS_DEC: case ACTION_SETTINGS_DECREPEAT: +#ifdef SANSA_E200 + global_settings.volume++; +#else global_settings.volume--; +#endif if(global_settings.volume < sound_min(SOUND_VOLUME)) global_settings.volume = sound_min(SOUND_VOLUME); sound_set_volume(global_settings.volume); @@ -967,7 +983,7 @@ } else { -#if CONFIG_CODEC == SWCODEC +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); #else radio_stop(); Index: apps/playback.c =================================================================== --- apps/playback.c (revision 13475) +++ apps/playback.c (working copy) @@ -3302,7 +3302,7 @@ static void audio_play_start(size_t offset) { -#if defined(HAVE_RECORDING) || CONFIG_TUNER +#if defined(HAVE_RECORDING) && CONFIG_TUNER rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); #endif Index: apps/debug_menu.c =================================================================== --- apps/debug_menu.c (revision 13475) +++ apps/debug_menu.c (working copy) @@ -1999,7 +1999,28 @@ snprintf(buf, sizeof buf, "HW detected: %s", fm_detected?"yes":"no"); lcd_puts(0, row++, buf); +#if (CONFIG_TUNER & LV24020LP) + snprintf(buf, sizeof buf, "Sanyo IF: %02X", + sanyo_get(RADIO_IF_MEASUREMENT)); + lcd_puts(0, row++, buf); + + snprintf(buf, sizeof buf, "CTRL_STAT: %02X", + sanyo_get(RADIO_ALL) ); + lcd_puts(0, row++, buf); + + snprintf(buf, sizeof buf, "MSS_FM: %d Hz", + (sanyo_get(11) ) ); + lcd_puts(0, row++, buf); + snprintf(buf, sizeof buf, "MSS_SD: %d Hz", + (sanyo_get(12) ) ); + lcd_puts(0, row++, buf); + + snprintf(buf, sizeof buf, "MSS_IF: %d Hz", + (sanyo_get(13) ) ); + lcd_puts(0, row++, buf); + +#endif #if (CONFIG_TUNER & S1A0903X01) snprintf(buf, sizeof buf, "Samsung regs: %08X", samsung_get(RADIO_ALL)); Index: apps/keymaps/keymap-e200.c =================================================================== --- apps/keymaps/keymap-e200.c (revision 13475) +++ apps/keymaps/keymap-e200.c (working copy) @@ -225,6 +225,17 @@ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), }; /* button_context_bmark */ +/** FM Radio Screen **/ +static const struct button_mapping button_context_radio[] = { + { ACTION_FM_MENU, BUTTON_DOWN, BUTTON_NONE }, + { ACTION_FM_PRESET, BUTTON_SELECT, BUTTON_NONE }, + { ACTION_FM_STOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP }, + { ACTION_FM_MODE, BUTTON_REC, BUTTON_NONE }, + { ACTION_FM_EXIT, BUTTON_POWER, BUTTON_NONE }, + { ACTION_FM_PLAY, BUTTON_UP|BUTTON_REL, BUTTON_UP }, + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) +}; /* button_context_radio */ + /* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */ const struct button_mapping* get_context_mapping(int context) { @@ -259,6 +270,8 @@ return button_context_yesno; case CONTEXT_BOOKMARKSCREEN: return button_context_bmark; + case CONTEXT_FM: + return button_context_radio; case CONTEXT_QUICKSCREEN: return button_context_quickscreen; case CONTEXT_PITCHSCREEN: Index: firmware/export/tuner.h =================================================================== --- firmware/export/tuner.h (revision 13475) +++ firmware/export/tuner.h (working copy) @@ -49,6 +49,9 @@ #if CONFIG_TUNER == S1A0903X01 /* FM recorder */ #define radio_set samsung_set #define radio_get samsung_get +#elif CONFIG_TUNER == LV24020LP /* Sansa */ +#define radio_set sanyo_set +#define radio_get sanyo_get #elif CONFIG_TUNER == TEA5767 /* iRiver, iAudio */ #define radio_set philips_set #define radio_get philips_get @@ -65,6 +68,12 @@ int samsung_get(int setting); #endif /* CONFIG_TUNER & S1A0903X01 */ +#if (CONFIG_TUNER & LV24020LP) +int sanyo_set(int setting, int value); +int sanyo_get(int setting); +void tuner_sanyo_init(void); +#endif /* CONFIG_TUNER & LV24020LP */ + #if (CONFIG_TUNER & TEA5767) struct philips_dbg_info { @@ -92,10 +101,17 @@ _radio_set = samsung_set; _radio_get = samsung_get; } + + #endif + +#if CONFIG_TUNER == LV24020LP +tuner_sanyo_init(); #endif } #endif /* #if CONFIG_TUNER */ #endif + +#endif Index: firmware/export/config.h =================================================================== --- firmware/export/config.h (revision 13475) +++ firmware/export/config.h (working copy) @@ -29,6 +29,7 @@ /* CONFIG_TUNER (note these are combineable bit-flags) */ #define S1A0903X01 0x01 /* Samsung */ #define TEA5767 0x02 /* Philips */ +#define LV24020LP 0x04 /* Sanyo */ /* CONFIG_CODEC */ #define MAS3587F 3587 Index: firmware/export/config-e200.h =================================================================== --- firmware/export/config-e200.h (revision 13475) +++ firmware/export/config-e200.h (working copy) @@ -74,8 +74,7 @@ #define AB_REPEAT_ENABLE 1 /* FM Tuner */ -/*#define CONFIG_TUNER TEA5767 -#define CONFIG_TUNER_XTAL 32768 *//* TODO: what is this? */ +#define CONFIG_TUNER LV24020LP /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 13475) +++ firmware/SOURCES (working copy) @@ -153,6 +153,10 @@ drivers/fmradio_i2c.c tuner_philips.c #endif /* (CONFIG_TUNER & TEA5767) */ +#if (CONFIG_TUNER & LV24020LP) +drivers/fmradio.c +tuner_sanyo.c +#endif /* (CONFIG_TUNER & LV24020LP) */ #endif /*SIMULATOR */ #endif /* CONFIG_TUNER */ Index: firmware/target/arm/audio-pp.c =================================================================== --- firmware/target/arm/audio-pp.c (revision 13475) +++ firmware/target/arm/audio-pp.c (working copy) @@ -70,6 +70,7 @@ break; #endif #ifdef HAVE_FMRADIO_REC + static int recording = 0; /* temp fix */ case AUDIO_SRC_FMRADIO: /* recording and playback */ if (!recording) audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN); Index: firmware/tuner_sanyo.c =================================================================== --- firmware/tuner_sanyo.c (revision 0) +++ firmware/tuner_sanyo.c (revision 0) @@ -0,0 +1,703 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Tuner driver for the Sanyo LV24020LP + * + * Copyright (C) 2007 Ivan Zupan + * + * 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 +#include +#include "config.h" +#include "kernel.h" +#include "tuner.h" /* tuner abstraction interface */ +#include "fmradio.h" /* physical interface driver */ +#include "mpeg.h" +#include "sound.h" +#include "pp5024.h" +#include "system.h" +#include "as3514.h" + + +#define FM_NRW_PIN 3 + +#define FM_CLOCK_PIN 4 + +#define FM_DATA_PIN 5 +#define FM_CLK_DELAY 1 + + +#define BLK1 0x01 +#define BLK2 0x02 +#define CHIP_ID 0x00 +#define BLK_SEL 0x01 +#define MSRC_SEL 0x02 +/* */ + #define MSR_O (1 << 7) + #define AFC_LVL (1 << 6) + #define AFC_SPD (1 << 5) + #define MSS_SD (1 << 2) + #define MSS_FM (1 << 1) + #define MSS_IF (1 << 0) +/* */ +#define FM_OSC 0x03 +#define SD_OSC 0x04 +#define IF_OSC 0x05 +#define CNT_CTRL 0x06 +/* */ + #define CNT1_CLR (1 << 7) + #define CTAB2 (1 << 6) + #define CTAB1 (1 << 5) + #define CTAB0 (1 << 4) + #define SWP_CNT_L (1 << 3) + #define CNT_EN (1 << 2) + #define CNT_SEL (1 << 1) + #define CNT_SET (1 << 0) +/* */ +#define IRQ_MSK 0x08 +/* */ + #define IM_MS (1 << 6) + #define IRQ_LVL (1 << 3) + #define IM_AFC (1 << 2) + #define IM_FS (1 << 1) + #define IM_CNT2 (1 << 0) +/* */ +#define FM_CAP 0x09 +#define CNT_L 0x0A +#define CNT_H 0x0B +#define CTRL_STAT 0x0c +#define RADIO_STAT 0x0D +/* */ + #define RSS_MS (1 << 7) +/* */ + +#define IRQ_ID 0x0E +/* */ + #define II_CNT2 (1 << 5) + #define II_AFC (1 << 3) + #define II_FS_MS (1 << 0) +/* */ +#define IRQ_OUT 0x0F + +/* block 2 registers */ +#define BLK_SEL 0x01 +#define RADIO_CTRL1 0x02 +/* */ + #define EN_MEAS (1 << 7) + #define EN_AFC (1 << 6) + #define DIR_AFC (1 << 3) + #define RST_AFC (1 << 2) +/* */ +#define IF_CENTER 0x03 +#define IF_BW 0x05 +#define RADIO_CTRL2 0x06 +/* */ + #define VREF2 (1 << 7) + #define VREF (1 << 6) + #define STABI_BP (1 << 5) + #define IF_PM_L (1 << 4) + #define AGC_SP (1 << 1) + #define AM_ANT_BSW (1 << 0) +/* */ +#define RADIO_CTRL3 0x07 +/* */ + #define AGC_SLVL (1 << 7) + #define VOLSH (1 << 6) + #define AMUTE_L (1 << 4) + #define SE_FM (1 << 3) + +/* */ + + +#define STEREO_CTRL 0x08 +/* */ + #define FRCST (1 << 7) + #define FMCS2 (1 << 6) + #define FMCS1 (1 << 5) + #define FMCS0 (1 << 4) + #define AUTOSSR (1 << 3) + #define PILTCA (1 << 2) + #define SD_PM (1 << 1) + #define ST_M (1 << 0) +/* */ +#define AUDIO_CTRL1 0x09 +/* */ + #define VOL_LVL (1 << 0) +/* */ + +#define AUDIO_CTRL2 0x0A +/* */ + #define DEEMP (1 << 5) +/* */ +#define PW_SCTRL 0x0B +/* */ + #define SS_CTRL2 (1 << 7) + #define SS_CTRL1 (1 << 6) + #define SS_CTRL0 (1 << 5) + #define SM_CTRL2 (1 << 4) + #define SM_CTRL1 (1 << 3) + #define SM_CTRL0 (1 << 2) + #define PW_RAD (1 << 0) +/* */ + +void enableAFC(bool enabled); +void tuner_sanyo_init(void); +void tuner_sanyo_write(unsigned char address, unsigned char data); +unsigned char tuner_sanyo_read(unsigned char address); +unsigned char FM_CAP_logical_to_physical(unsigned char in); +unsigned char logical_to_physical(unsigned char in); +unsigned char physical_to_logical(unsigned char in); +unsigned int tuner_measure(unsigned char type); +int CalculateCoeff(int freq_hz); +int interpolateX( int ExpectedY, int x1, int x2, int y1, int y2); +int interpolateY( int ExpectedY, int x1, int x2, int y1, int y2); +void setFrequency(int freq_hz, int PrecisionLevel); +double pow(double x, long p); + + +static int freq_fine = 30; + +const int SwOscLow = 30; +const int SwOscHigh = 200; +const int SwCapLow = 0; +const int SwCapHigh = 191; +/* used by setFrequency */ +static int Coef00 = 0; +static int Coeff01= 0; +static int Coef10= 0; +static int Coeff11= 0; + +/* stores tuners current frequency values */ +int curr_freq = 0; +int wanted_freq = 0; + +bool radio_power(bool status) +{ + (void) status; + tuner_sanyo_write(BLK_SEL, BLK1); + return (tuner_sanyo_read(CHIP_ID) == 0x09); /* if tuner is present, CHIP ID is 0x09 */ +} + +bool radio_powered(void) +{ + return true; +} + + +int sanyo_set(int setting, int value) +{ + int val = 1; + switch(setting) + { + case RADIO_SLEEP: + break; + + case RADIO_FREQUENCY: + /* this is really a hack until we figure out how to calculate the values */ + + enableAFC(false); + wanted_freq = (value / 1000) ; + setFrequency(wanted_freq, 0); + + tuner_sanyo_write(FM_OSC, logical_to_physical(SwOscLow)); + + freq_fine = SwOscLow; + curr_freq = tuner_measure(MSS_FM); + while(wanted_freq < curr_freq) + { + freq_fine++; + tuner_sanyo_write(FM_OSC, logical_to_physical(freq_fine)); + curr_freq = tuner_measure(MSS_FM); + } + + enableAFC(true); + break; + + case RADIO_SCAN_FREQUENCY: + sanyo_set(RADIO_FREQUENCY, value); + sleep(HZ/30); + val = sanyo_get(RADIO_TUNED); + break; + + case RADIO_MUTE: + tuner_sanyo_write(BLK_SEL, BLK2); + if(value) + tuner_sanyo_write(RADIO_CTRL3, 0x88); + else + tuner_sanyo_write(RADIO_CTRL3, 0x98); + + break; + + default: + val = -1; + } + + return val; +} + + +int sanyo_get(int setting) +{ + int val = -1; + switch(setting) + { + case RADIO_IF_MEASUREMENT: + tuner_sanyo_write(BLK_SEL, BLK1); + return tuner_sanyo_read(RADIO_STAT); + break; + + case RADIO_ALL: + tuner_sanyo_write(BLK_SEL, BLK1); + return tuner_sanyo_read(CTRL_STAT); + break; + + case RADIO_TUNED: + tuner_sanyo_write(BLK_SEL, BLK1); + val = ((tuner_sanyo_read(RADIO_STAT)) < 135); + break; + + break; + case RADIO_STEREO: + tuner_sanyo_write(BLK_SEL, BLK1); + if (tuner_sanyo_read(RADIO_STAT) & RSS_MS) + val = true; + else + val = false; + break; + + case RADIO_PRESENT: + tuner_sanyo_write(BLK_SEL, BLK1); + val = (tuner_sanyo_read(CHIP_ID) == 0x09); + break; + /* for testing only */ + case 11: + return tuner_measure(MSS_FM); + break; + case 12: + return tuner_measure(MSS_SD); + break; + case 13: + return tuner_measure(MSS_IF); + break; + } + return val; +} + + +/* this is from the datasheet (pseudocode). + So far, only PrecisionLevel 0 works +*/ +void setFrequency(int freq_hz, int PrecisionLevel) +{ + int MeasureTime, CorFreq; + tuner_sanyo_write(BLK_SEL, BLK1); + int count = 0; + MeasureTime = 0; + CorFreq = 0; + + if ((PrecisionLevel == 1 )|| (PrecisionLevel == 2)) + { + MeasureTime = 32; + CorFreq = 32; + } + else if (PrecisionLevel == 3) + { + MeasureTime = 64; + CorFreq = 16; + } + CorFreq = CorFreq * 256; // For RF –frequency: DividerFactor=256 + + int Coef = CalculateCoeff(freq_hz); + int CapValue = interpolateX(Coef, SwCapLow, SwCapHigh, Coef00, Coeff01); + tuner_sanyo_write(FM_OSC, logical_to_physical(SwOscLow)); + + bool done = false; + int CoefLo, CoefHi, CoefRange, CoefCur, Fcur, CoefFcur, CoefCor, CapNew; + while(!done && count < 30) + { + + CoefLo = interpolateY(CapValue, SwCapLow, SwCapHigh, Coef00, Coeff01); + CoefHi = interpolateY(CapValue, SwCapLow, SwCapHigh, Coef10, Coeff11); + CoefRange = CoefLo - CoefHi; + + + tuner_sanyo_write(FM_CAP, FM_CAP_logical_to_physical(CapValue)); + if(MeasureTime != 0) + { + Fcur = tuner_measure(MSS_FM); + CoefFcur = CalculateCoeff(Fcur); + CoefCor = CalculateCoeff(Fcur + CorFreq); + CoefLo = CoefFcur + CoefCor; + CoefCur = CoefLo; + CoefHi = CoefCur - CoefRange - CoefCor; + } + else + { + CoefCur = CoefLo; + } + if(Coef >= CoefLo && Coef <= CoefHi) + { + int OscValue = interpolateX(Coef, SwOscLow, SwOscHigh, CoefLo, CoefHi); + tuner_sanyo_write(FM_OSC, logical_to_physical(OscValue)); // right? + if(OscValue >= SwOscLow && OscValue <= SwOscHigh) + done = true; + + } + + if(!done) + { + CapNew = interpolateX(Coef, CapValue, SwCapHigh, CoefCur, Coeff01); + if (CapNew == CapValue) + { + if (Coef < CoefCur) + CapValue = CapValue + 1; + else + CapValue = CapValue - 1; + } + else + { + CapValue = CapNew; + } + } + + count++; + } +} + + +/* enables auto frequency centering */ +void enableAFC(bool enabled) +{ + + tuner_sanyo_write(BLK_SEL, BLK2); + if (enabled) + { + tuner_sanyo_write(RADIO_CTRL1, 0x57); + tuner_sanyo_write(RADIO_CTRL1, 0x53); + } + else + { + tuner_sanyo_write(RADIO_CTRL1, 0x17); + } + +} + +unsigned char logical_to_physical(unsigned char in) +{ + return 255-in; +} + +unsigned char physical_to_logical(unsigned char in) +{ + return 255-in; +} + +unsigned char FM_CAP_logical_to_physical(unsigned char in) +{ + if (in < 64) + return (255-in); + else + return (255-64-in); +} + +/* this performs measurements of IF, FM and Stereo frequencies +Input can be: MSS_FM, MSS_IF, MSS_SD */ +unsigned int tuner_measure(unsigned char type) +{ + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40|type); + tuner_sanyo_write(CNT_CTRL, 0x08); + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL1, 0x13|EN_MEAS); + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(CNT_CTRL, 0x08|(1<<7)); + tuner_sanyo_write(CNT_CTRL, 0x08); + tuner_sanyo_write(CNT_CTRL, 0x08|CNT_EN); + GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN);/* NR_W low */ + udelay(16000); + GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN);/* NR_W high */ + tuner_sanyo_write(CNT_CTRL, 0x08); + unsigned char in1 = tuner_sanyo_read(CNT_H); + unsigned char in2 = tuner_sanyo_read(CNT_L); + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL1, 0x13); + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40); + + + + unsigned int finval = (in1 << 8) | in2; + + if (type == MSS_FM) + return ((finval/16)*256); + else + return (finval/16); + + +} + +int interpolateX( int ExpectedY, int x1, int x2, int y1, int y2) +{ +if (y1 == y2) + return 0; +else + return ( (((ExpectedY-y1)*(x2-x1))/((y2-y1))+x1) ); + +} + + +int interpolateY( int ExpectedX, int x1, int x2, int y1, int y2) +{ +if (x1 == x2) + return 0; +else + return (((ExpectedX-x1)*(y2-y1))/(x2-x1))+y1; + +} + +int CalculateCoeff(int freq_hz) +{ + int A1 = pow(2, 32) - 1; + int A2 = pow(2, 16); + int A3 = pow(2, 8); + + int fkHz = freq_hz/1000; +if (fkHz == 0) + return 0; +else + return ( (( (A1 / freq_hz) * A2) / freq_hz ) * A3 ); + + +} + + +void tuner_sanyo_init(void) +{ + + + /* init mystery amplification device */ + DEV_INIT &= ~(1 << 11); + outl(inl(0x70000084) |= 0x1, 0x70000084); + outl(inl(0x70000080) |= 0x4, 0x70000080); + udelay(5); + + GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); + GPIOH_OUTPUT_EN |= (1 << FM_CLOCK_PIN); + GPIOH_ENABLE |= (1 << FM_CLOCK_PIN); + + GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); + GPIOH_ENABLE |= (1 << FM_DATA_PIN); + + GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); + GPIOH_OUTPUT_EN |= (1 << FM_NRW_PIN); + GPIOH_ENABLE |= (1 << FM_NRW_PIN); + + + /* from datasheet, default values */ + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40); + tuner_sanyo_write(FM_OSC, 0x80); + tuner_sanyo_write(SD_OSC, 0x80); + tuner_sanyo_write(IF_OSC, 0x80); + tuner_sanyo_write(CNT_CTRL, 0x08); + tuner_sanyo_write(IRQ_MSK, 0x00); + tuner_sanyo_write(FM_CAP, 0x80); + + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL1, 0x53); + + tuner_sanyo_write(IF_CENTER, 0x80); + + /* this may not be right */ + unsigned char freq = physical_to_logical(0x80) * 0.65; + freq = logical_to_physical(freq); + + tuner_sanyo_write(IF_BW, freq); + + tuner_sanyo_write(RADIO_CTRL2, 0x10); + tuner_sanyo_write(RADIO_CTRL3, 0x88); + tuner_sanyo_write(STEREO_CTRL, 0x48); + tuner_sanyo_write(AUDIO_CTRL1, 0x77); + tuner_sanyo_write(AUDIO_CTRL2, 0xC0); /* deemphasis 50us */ + tuner_sanyo_write(PW_SCTRL, 0x6D); + + /* some value is wrong below, and causes a whining sound */ + /* Datsheet step 2 */ + + /* This needs to be verifed, thankfully the tuner keeps the settings from OF + so the below is not mandatory + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL1, 0x53|EN_MEAS); + tuner_sanyo_write(RADIO_CTRL2, 0x10|IF_PM_L); + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40|MSS_IF); + tuner_sanyo_write(IF_OSC, 110); + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(IF_CENTER, logical_to_physical(110)); + tuner_sanyo_write(IF_BW, logical_to_physical(110*0.65)); + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40); + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL2, 0x10); + tuner_sanyo_write(RADIO_CTRL1, 0x53); +*/ + /* Datsheet step 3 */ + /* + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(RADIO_CTRL1, 0x53|EN_MEAS); + tuner_sanyo_write(STEREO_CTRL, 0x48|SD_PM); + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(MSRC_SEL, 0x40|MSS_SD); + tuner_sanyo_write(SD_OSC, 38); + tuner_sanyo_write(MSRC_SEL, 0x40); + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(STEREO_CTRL, 0x48); + tuner_sanyo_write(RADIO_CTRL1, 0x53); +*/ + /* set various audio level settings */ + tuner_sanyo_write(BLK_SEL, BLK2); + tuner_sanyo_write(AUDIO_CTRL1, 0x00); + tuner_sanyo_write(STEREO_CTRL, 0x48|FRCST); + tuner_sanyo_write(PW_SCTRL, 0x71); + + /* from the datasheet, used to calculate what values to set + in setFrequency + */ + tuner_sanyo_write(BLK_SEL, BLK1); + tuner_sanyo_write(FM_OSC, logical_to_physical(SwOscLow)); + tuner_sanyo_write(FM_CAP, FM_CAP_logical_to_physical(SwCapLow)); + int f00 = tuner_measure(MSS_FM); + Coef00 = CalculateCoeff(f00); + tuner_sanyo_write(FM_CAP, FM_CAP_logical_to_physical(SwCapHigh)); + int f01 = tuner_measure(MSS_FM); + Coeff01 = CalculateCoeff(f01); + tuner_sanyo_write(FM_OSC, logical_to_physical(SwOscHigh)); + tuner_sanyo_write(FM_CAP, FM_CAP_logical_to_physical(SwCapLow)); + int f10 = tuner_measure(MSS_FM); + Coef10 = CalculateCoeff(f10); + tuner_sanyo_write(FM_CAP, FM_CAP_logical_to_physical(SwCapHigh)); + int f11 = tuner_measure(MSS_FM); + Coeff11 = CalculateCoeff(f11); + +} + + +void tuner_sanyo_write(unsigned char address, unsigned char data) +{ + +GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN); +GPIOH_OUTPUT_EN |= (1 << FM_DATA_PIN); + +udelay(FM_CLK_DELAY); + int i = 0; + /* data first */ + for(i=0;i<8;i++) + { + GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN); + if ((data >> i) & 0x1) + GPIOH_OUTPUT_VAL |= (1 << FM_DATA_PIN); + else + GPIOH_OUTPUT_VAL &= ~(1 << FM_DATA_PIN); + GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); + udelay(FM_CLK_DELAY); + } + /* then address */ + for(i=0;i<8;i++) + { + GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN); + if ((address >> i) & 0x1) + GPIOH_OUTPUT_VAL |= (1 << FM_DATA_PIN); + else + GPIOH_OUTPUT_VAL &= ~(1 << FM_DATA_PIN); + GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); + udelay(FM_CLK_DELAY); + } + + GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); + GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); + +} + +unsigned char tuner_sanyo_read(unsigned char address) +{ + +GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN); +GPIOH_OUTPUT_EN |= (1 << FM_DATA_PIN); + +udelay(FM_CLK_DELAY); + + + unsigned char toread = 0; + + int i = 0; + /* address */ + for(i=0;i<8;i++) + { + GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN); + if ((address >> i) & 0x1) + GPIOH_OUTPUT_VAL |= (1 << FM_DATA_PIN); + else + GPIOH_OUTPUT_VAL &= ~(1 << FM_DATA_PIN); + + GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); + udelay(FM_CLK_DELAY); + } + GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); + GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); + + toread = 0; + for(i=0;i<8;i++) + { + GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN); + udelay(FM_CLK_DELAY); + int res = GPIOH_INPUT_VAL & (1 << FM_DATA_PIN); + if (res) + toread |= (1 << i); + + GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); + + } + + return toread; + +} +/* from libg++ */ +double pow(double x, long p) +{ + if (p == 0) + return 1.0; + else if (x == 0.0) + return 0.0; + else + { + if (p < 0) + { + p = -p; + x = 1.0 / x; + } + + double r = 1.0; + for(;;) + { + if (p & 1) + r *= x; + if ((p >>= 1) == 0) + return r; + else + x *= x; + } + } +} + Index: firmware/drivers/audio/as3514.c =================================================================== --- firmware/drivers/audio/as3514.c (revision 13475) +++ firmware/drivers/audio/as3514.c (working copy) @@ -114,10 +114,10 @@ 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 */ -#if 0 - as3514_write(LINE_IN1_R, 0x36); /* unmute lineIn 1 and set gain */ - as3514_write(LINE_IN1_L, 0x36); /* unmute lineIn 1 and set gain */ -#endif + + as3514_write(LINE_IN1_R, 0x30); /* unmute lineIn 1 and set gain */ + as3514_write(LINE_IN1_L, 0x30); /* unmute lineIn 1 and set gain */ + as3514_write(PLLMODE, 0x00); /* read all reg values */ Index: firmware/drivers/fmradio.c =================================================================== --- firmware/drivers/fmradio.c (revision 13475) +++ firmware/drivers/fmradio.c (working copy) @@ -23,7 +23,7 @@ #include "debug.h" #include "system.h" -#if CONFIG_TUNER +#if CONFIG_TUNER && !(CONFIG_TUNER & LV24020LP) /* Signals: DI (Data In) - PB0 (doubles as data pin for the LCD)