diff options
Diffstat (limited to 'firmware/drivers/tuner/s1a0903x01.c')
-rw-r--r-- | firmware/drivers/tuner/s1a0903x01.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/firmware/drivers/tuner/s1a0903x01.c b/firmware/drivers/tuner/s1a0903x01.c new file mode 100644 index 0000000000..cdeba2b3b4 --- /dev/null +++ b/firmware/drivers/tuner/s1a0903x01.c @@ -0,0 +1,172 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Tuner "middleware" for Samsung S1A0903X01 chip + * + * Copyright (C) 2003 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 <stdbool.h> +#include <stdlib.h> +#include "config.h" +#include "kernel.h" +#include "tuner.h" /* tuner abstraction interface */ +#include "fmradio.h" /* physical interface driver */ +#include "mpeg.h" +#include "sound.h" + +#define DEFAULT_IN1 0x100003 /* Mute */ +#define DEFAULT_IN2 0x140884 /* 5kHz, 7.2MHz crystal */ +#define PLL_FREQ_STEP 10000 + +static int fm_in1; +static int fm_in2; +static int fm_present = -1; /* unknown */ + +/* tuner abstraction layer: set something to the tuner */ +int s1a0903x01_set(int setting, int value) +{ + int val = 1; + + switch(setting) + { + case RADIO_SLEEP: + if (!value) + { /* wakeup: just unit */ + fm_in1 = DEFAULT_IN1; + fm_in2 = DEFAULT_IN2; + fmradio_set(1, fm_in1); + fmradio_set(2, fm_in2); + } + /* else we have no sleep mode? */ + break; + + case RADIO_FREQUENCY: + { + int pll_cnt; +#if CONFIG_CODEC == MAS3587F + /* Shift the MAS internal clock away for certain frequencies to + * avoid interference. */ + int pitch = 1000; + + /* 4th harmonic falls in the FM frequency range */ + int if_freq = 4 * mpeg_get_mas_pllfreq(); + + /* shift the mas harmonic >= 300 kHz away using the direction + * which needs less shifting. */ + if (value < if_freq) + { + if (if_freq - value < 300000) + pitch = 1003 - (if_freq - value) / 100000; + } + else + { + if (value - if_freq < 300000) + pitch = 997 + (value - if_freq) / 100000; + } + sound_set_pitch(pitch); +#endif + /* We add the standard Intermediate Frequency 10.7MHz + ** before calculating the divisor + ** The reference frequency is set to 50kHz, and the VCO + ** output is prescaled by 2. + */ + + pll_cnt = (value + 10700000) / (PLL_FREQ_STEP/2) / 2; + + /* 0x100000 == FM mode + ** 0x000002 == Microprocessor controlled Mute + */ + fm_in1 = (fm_in1 & 0xfff00007) | (pll_cnt << 3); + fmradio_set(1, fm_in1); + break; + } + + case RADIO_SCAN_FREQUENCY: + /* Tune in and delay */ + s1a0903x01_set(RADIO_FREQUENCY, value); + sleep(1); + /* Start IF measurement */ + fm_in1 |= 4; + fmradio_set(1, fm_in1); + sleep(1); + val = s1a0903x01_get(RADIO_TUNED); + break; + + case RADIO_MUTE: + fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0); + fmradio_set(1, fm_in1); + break; + + case RADIO_FORCE_MONO: + fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4); + fmradio_set(2, fm_in2); + break; + /* NOTE: These were only zeroed when starting the tuner from OFF + but the default values already set them to 0. */ +#if 0 + case S1A0903X01_IF_MEASUREMENT: + fm_in1 = (fm_in1 & 0xfffffffb) | (value?4:0); + fmradio_set(1, fm_in1); + break; + + case S1A0903X01_SENSITIVITY: + fm_in2 = (fm_in2 & 0xffff9fff) | ((value & 3) << 13); + fmradio_set(2, fm_in2); + break; +#endif + default: + val = -1; + } + + return val; +} + +/* tuner abstraction layer: read something from the tuner */ +int s1a0903x01_get(int setting) +{ + int val = -1; + switch(setting) + { + case RADIO_PRESENT: + if (fm_present == -1) + { +#ifdef HAVE_TUNER_PWR_CTRL + bool fmstatus = tuner_power(true); +#endif + /* 5kHz, 7.2MHz crystal, test mode 1 */ + fmradio_set(2, 0x140885); + fm_present = (fmradio_read(0) == 0x140885); +#ifdef HAVE_TUNER_PWR_CTRL + if (!fmstatus) + tuner_power(false); +#endif + } + + val = fm_present; + break; + + case RADIO_TUNED: + val = fmradio_read(3); + val = abs(10700 - ((val & 0x7ffff) / 8)) < 50; /* convert to kHz */ + break; + + case RADIO_STEREO: + val = fmradio_read(3); + val = ((val & 0x100000) ? true : false); + break; + } + return val; +} |