diff options
Diffstat (limited to 'firmware')
19 files changed, 491 insertions, 275 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 7e26ca0bc4..2db8e9e568 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -151,17 +151,18 @@ drivers/rtc/rtc_as3514.c /* Tuner */ #if CONFIG_TUNER #ifndef SIMULATOR +tuner.c +#if (CONFIG_TUNER & LV24020LP) +drivers/tuner/lv24020lp.c +#endif /* (CONFIG_TUNER & LV24020LP) */ #if (CONFIG_TUNER & S1A0903X01) drivers/fmradio.c -tuner_samsung.c +drivers/tuner/s1a0903x01.c #endif /* (CONFIG_TUNER & S1A0903X01) */ #if (CONFIG_TUNER & TEA5767) drivers/fmradio_i2c.c -tuner_philips.c +drivers/tuner/tea5767.c #endif /* (CONFIG_TUNER & TEA5767) */ -#if (CONFIG_TUNER & LV24020LP) -tuner_sanyo.c -#endif /* (CONFIG_TUNER & LV24020LP) */ #endif /*SIMULATOR */ #endif /* CONFIG_TUNER */ diff --git a/firmware/drivers/power.c b/firmware/drivers/power.c index eb69fcec27..50117dd321 100644 --- a/firmware/drivers/power.c +++ b/firmware/drivers/power.c @@ -37,12 +37,12 @@ bool charger_enabled; static bool powered = false; -bool radio_powered(void) +bool tuner_powered(void) { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/tuner_sanyo.c b/firmware/drivers/tuner/lv24020lp.c index 6e732975b6..9ec68f9a27 100644 --- a/firmware/tuner_sanyo.c +++ b/firmware/drivers/tuner/lv24020lp.c @@ -25,11 +25,9 @@ #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" #ifndef BOOTLOADER @@ -234,7 +232,7 @@ static int fd_log = -1; #define TUNER_PRESENCE_CHECKED (1 << 3) static unsigned tuner_status = 0; -static unsigned char sanyo_regs[0x1c]; +static unsigned char lv24020lp_regs[0x1c]; static const int sw_osc_low = 10; /* 30; */ static const int sw_osc_high = 240; /* 200; */ @@ -253,7 +251,7 @@ static inline bool tuner_awake(void) } /* send a byte to the tuner - expects write mode to be current */ -static void tuner_sanyo_send_byte(unsigned int byte) +static void lv24020lp_send_byte(unsigned int byte) { int i; @@ -274,7 +272,7 @@ static void tuner_sanyo_send_byte(unsigned int byte) } /* end a write cycle on the tuner */ -static void tuner_sanyo_end_write(void) +static void lv24020lp_end_write(void) { /* switch back to read mode */ GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); @@ -282,7 +280,7 @@ static void tuner_sanyo_end_write(void) } /* prepare a write cycle on the tuner */ -static unsigned int tuner_sanyo_begin_write(unsigned int address) +static unsigned int lv24020lp_begin_write(unsigned int address) { /* Get register's block, translate address */ unsigned int blk = (address >= BLK2_START) ? @@ -297,29 +295,29 @@ static unsigned int tuner_sanyo_begin_write(unsigned int address) udelay(FM_CLK_DELAY); /* current block == register block? */ - if (blk == sanyo_regs[BLK_SEL]) + if (blk == lv24020lp_regs[BLK_SEL]) return address; /* switch block */ - sanyo_regs[BLK_SEL] = blk; + lv24020lp_regs[BLK_SEL] = blk; /* data first */ - tuner_sanyo_send_byte(blk); + lv24020lp_send_byte(blk); /* then address */ - tuner_sanyo_send_byte(BLK_SEL); + lv24020lp_send_byte(BLK_SEL); - tuner_sanyo_end_write(); + lv24020lp_end_write(); udelay(FM_CLK_DELAY); } } /* write a byte to a tuner register */ -static void tuner_sanyo_write(unsigned int address, unsigned int data) +static void lv24020lp_write(unsigned int address, unsigned int data) { /* shadow logical values but do logical=>physical remappings on some registers' data. */ - sanyo_regs[address] = data; + lv24020lp_regs[address] = data; switch (address) { @@ -340,39 +338,39 @@ static void tuner_sanyo_write(unsigned int address, unsigned int data) break; } - address = tuner_sanyo_begin_write(address); + address = lv24020lp_begin_write(address); /* data first */ - tuner_sanyo_send_byte(data); + lv24020lp_send_byte(data); /* then address */ - tuner_sanyo_send_byte(address); + lv24020lp_send_byte(address); - tuner_sanyo_end_write(); + lv24020lp_end_write(); } /* helpers to set/clear register bits */ -static void tuner_sanyo_write_or(unsigned int address, unsigned int bits) +static void lv24020lp_write_or(unsigned int address, unsigned int bits) { - tuner_sanyo_write(address, sanyo_regs[address] | bits); + lv24020lp_write(address, lv24020lp_regs[address] | bits); } -static void tuner_sanyo_write_and(unsigned int address, unsigned int bits) +static void lv24020lp_write_and(unsigned int address, unsigned int bits) { - tuner_sanyo_write(address, sanyo_regs[address] & bits); + lv24020lp_write(address, lv24020lp_regs[address] & bits); } /* read a byte from a tuner register */ -static unsigned int tuner_sanyo_read(unsigned int address) +static unsigned int lv24020lp_read(unsigned int address) { int i; unsigned int toread; - address = tuner_sanyo_begin_write(address); + address = lv24020lp_begin_write(address); /* address */ - tuner_sanyo_send_byte(address); + lv24020lp_send_byte(address); - tuner_sanyo_end_write(); + lv24020lp_end_write(); /* data */ toread = 0; @@ -392,7 +390,7 @@ static unsigned int tuner_sanyo_read(unsigned int address) /* enables auto frequency centering */ static void enable_afc(bool enabled) { - unsigned int radio_ctrl1 = sanyo_regs[RADIO_CTRL1]; + unsigned int radio_ctrl1 = lv24020lp_regs[RADIO_CTRL1]; if (enabled) { @@ -405,7 +403,7 @@ static void enable_afc(bool enabled) radio_ctrl1 &= ~EN_AFC; } - tuner_sanyo_write(RADIO_CTRL1, radio_ctrl1); + lv24020lp_write(RADIO_CTRL1, radio_ctrl1); } static int calculate_coef(unsigned fkhz) @@ -439,25 +437,25 @@ static int tuner_measure(unsigned char type, int scale, int duration) return 0; /* enable measuring */ - tuner_sanyo_write_or(MSRC_SEL, type); - tuner_sanyo_write_and(CNT_CTRL, ~CNT_SEL); - tuner_sanyo_write_or(RADIO_CTRL1, EN_MEAS); + lv24020lp_write_or(MSRC_SEL, type); + lv24020lp_write_and(CNT_CTRL, ~CNT_SEL); + lv24020lp_write_or(RADIO_CTRL1, EN_MEAS); /* reset counter */ - tuner_sanyo_write_or(CNT_CTRL, CNT1_CLR); - tuner_sanyo_write_and(CNT_CTRL, ~CNT1_CLR); + lv24020lp_write_or(CNT_CTRL, CNT1_CLR); + lv24020lp_write_and(CNT_CTRL, ~CNT1_CLR); /* start counter, delay for specified time and stop it */ - tuner_sanyo_write_or(CNT_CTRL, CNT_EN); + lv24020lp_write_or(CNT_CTRL, CNT_EN); udelay(duration*1000 - 16); - tuner_sanyo_write_and(CNT_CTRL, ~CNT_EN); + lv24020lp_write_and(CNT_CTRL, ~CNT_EN); /* read tick count */ - finval = (tuner_sanyo_read(CNT_H) << 8) | tuner_sanyo_read(CNT_L); + finval = (lv24020lp_read(CNT_H) << 8) | lv24020lp_read(CNT_L); /* restore measure mode */ - tuner_sanyo_write_and(RADIO_CTRL1, ~EN_MEAS); - tuner_sanyo_write_and(MSRC_SEL, ~type); + lv24020lp_write_and(RADIO_CTRL1, ~EN_MEAS); + lv24020lp_write_and(MSRC_SEL, ~type); /* convert value */ if (type == MSS_FM) @@ -469,7 +467,7 @@ static int tuner_measure(unsigned char type, int scale, int duration) } /* set the FM oscillator frequency */ -static void sanyo_set_frequency(int freq) +static void set_frequency(int freq) { int coef, cap_value, osc_value; int f1, f2, x1, x2; @@ -494,7 +492,7 @@ static void sanyo_set_frequency(int freq) coef_00, coef_01); osc_value = sw_osc_low; - tuner_sanyo_write(FM_OSC, osc_value); + lv24020lp_write(FM_OSC, osc_value); /* Just in case - don't go into infinite loop */ for (count = 0; count < 30; count++) @@ -505,7 +503,7 @@ static void sanyo_set_frequency(int freq) coef_10, coef_11); int coef_fcur, cap_new, coef_cor, range; - tuner_sanyo_write(FM_CAP, cap_value); + lv24020lp_write(FM_CAP, cap_value); range = y1 - y0; f1 = tuner_measure(MSS_FM, 1, 16); @@ -554,7 +552,7 @@ static void sanyo_set_frequency(int freq) { int x2_new; - tuner_sanyo_write(FM_OSC, x2); + lv24020lp_write(FM_OSC, x2); f2 = tuner_measure(MSS_FM, 1, 16); if (abs(f2 - freq) <= 16) @@ -632,9 +630,9 @@ static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) static int if_setcmp(int regval) { - tuner_sanyo_write(IF_OSC, regval); - tuner_sanyo_write(IF_CENTER, regval); - tuner_sanyo_write(IF_BW, 65*regval/100); + lv24020lp_write(IF_OSC, regval); + lv24020lp_write(IF_CENTER, regval); + lv24020lp_write(IF_BW, 65*regval/100); if_set = tuner_measure(MSS_IF, 1000, 32); @@ -649,7 +647,7 @@ static int if_setcmp(int regval) static int sd_setcmp(int regval) { - tuner_sanyo_write(SD_OSC, regval); + lv24020lp_write(SD_OSC, regval); sd_set = tuner_measure(MSS_SD, 1000, 32); @@ -659,7 +657,7 @@ static int sd_setcmp(int regval) return sd_set < 38300 ? -1 : 1; } -static void sanyo_sleep(bool sleep) +static void set_sleep(bool sleep) { if (sleep || tuner_awake()) return; @@ -673,41 +671,41 @@ static void sanyo_sleep(bool sleep) enable_afc(false); /* 2. Calibrate the IF frequency at 110 kHz: */ - tuner_sanyo_write_and(RADIO_CTRL2, ~IF_PM_L); + lv24020lp_write_and(RADIO_CTRL2, ~IF_PM_L); fine_step_tune(if_setcmp, 0x80, 8); - tuner_sanyo_write_or(RADIO_CTRL2, IF_PM_L); + lv24020lp_write_or(RADIO_CTRL2, IF_PM_L); /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */ - tuner_sanyo_write_or(STEREO_CTRL, SD_PM); + lv24020lp_write_or(STEREO_CTRL, SD_PM); fine_step_tune(sd_setcmp, 0x80, 8); - tuner_sanyo_write_and(STEREO_CTRL, ~SD_PM); + lv24020lp_write_and(STEREO_CTRL, ~SD_PM); /* calculate FM tuning coefficients */ - tuner_sanyo_write(FM_CAP, sw_cap_low); - tuner_sanyo_write(FM_OSC, sw_osc_low); + lv24020lp_write(FM_CAP, sw_cap_low); + lv24020lp_write(FM_OSC, sw_osc_low); coef_00 = calculate_coef(tuner_measure(MSS_FM, 1, 64)); - tuner_sanyo_write(FM_CAP, sw_cap_high); + lv24020lp_write(FM_CAP, sw_cap_high); coef_01 = calculate_coef(tuner_measure(MSS_FM, 1, 64)); - tuner_sanyo_write(FM_CAP, sw_cap_low); - tuner_sanyo_write(FM_OSC, sw_osc_high); + lv24020lp_write(FM_CAP, sw_cap_low); + lv24020lp_write(FM_OSC, sw_osc_high); coef_10 = calculate_coef(tuner_measure(MSS_FM, 1, 64)); - tuner_sanyo_write(FM_CAP, sw_cap_high); + lv24020lp_write(FM_CAP, sw_cap_high); coef_11 = calculate_coef(tuner_measure(MSS_FM, 1, 64)); /* set various audio level settings */ - tuner_sanyo_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0)); - tuner_sanyo_write_or(RADIO_CTRL2, AGCSP); - tuner_sanyo_write_or(RADIO_CTRL3, VOLSH); - tuner_sanyo_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); - tuner_sanyo_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | - PW_RAD); + lv24020lp_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0)); + lv24020lp_write_or(RADIO_CTRL2, AGCSP); + lv24020lp_write_or(RADIO_CTRL3, VOLSH); + lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); + lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | + PW_RAD); } /** Public interfaces **/ -bool radio_power(bool status) +void lv24020lp_power(bool status) { static const unsigned char tuner_defaults[][2] = { @@ -733,38 +731,13 @@ bool radio_power(bool status) }; unsigned i; - bool powered = tuner_status & TUNER_POWERED; - - if (status == powered) - return powered; if (status) { - /* init mystery amplification device */ - outl(inl(0x70000084) | 0x1, 0x70000084); - udelay(5); - - /* When power up, host should initialize the 3-wire bus in host read - mode: */ - - /* 1. Set direction of the DATA-line to input-mode. */ - GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); - GPIOH_ENABLE |= (1 << FM_DATA_PIN); - - /* 2. Drive NR_W low */ - GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); - GPIOH_OUTPUT_EN |= (1 << FM_NRW_PIN); - GPIOH_ENABLE |= (1 << FM_NRW_PIN); - - /* 3. Drive CLOCK high */ - GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); - GPIOH_OUTPUT_EN |= (1 << FM_CLOCK_PIN); - GPIOH_ENABLE |= (1 << FM_CLOCK_PIN); - - tuner_status |= TUNER_POWERED; + tuner_status |= TUNER_POWERED | TUNER_PRESENCE_CHECKED; /* if tuner is present, CHIP ID is 0x09 */ - if (tuner_sanyo_read(CHIP_ID) == 0x09) + if (lv24020lp_read(CHIP_ID) == 0x09) { tuner_status |= TUNER_PRESENT; @@ -772,9 +745,9 @@ bool radio_power(bool status) follows: */ /* 1. Write default values to the registers: */ - sanyo_regs[BLK_SEL] = 0; /* Force a switch on the first */ + lv24020lp_regs[BLK_SEL] = 0; /* Force a switch on the first */ for (i = 0; i < ARRAYLEN(tuner_defaults); i++) - tuner_sanyo_write(tuner_defaults[i][0], tuner_defaults[i][1]); + lv24020lp_write(tuner_defaults[i][0], tuner_defaults[i][1]); /* Complete the startup calibration if the tuner is woken */ udelay(100000); @@ -782,76 +755,55 @@ bool radio_power(bool status) } else { - /* Power off and set all as inputs */ + /* Power off */ if (tuner_status & TUNER_PRESENT) - tuner_sanyo_write_and(PW_SCTRL, ~PW_RAD); - - GPIOH_OUTPUT_EN &= ~((1 << FM_DATA_PIN) | (1 << FM_NRW_PIN) | - (1 << FM_CLOCK_PIN)); - GPIOH_ENABLE &= ~((1 << FM_DATA_PIN) | (1 << FM_NRW_PIN) | - (1 << FM_CLOCK_PIN)); - - outl(inl(0x70000084) & ~0x1, 0x70000084); + lv24020lp_write_and(PW_SCTRL, ~PW_RAD); tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); } - - return powered; -} - -bool radio_powered(void) -{ - return (tuner_status & TUNER_POWERED) != 0; } -int sanyo_set(int setting, int value) +int lv24020lp_set(int setting, int value) { int val = 1; switch(setting) { case RADIO_SLEEP: - sanyo_sleep(value); + set_sleep(value); break; case RADIO_FREQUENCY: - sanyo_set_frequency(value); + set_frequency(value); break; case RADIO_SCAN_FREQUENCY: /* TODO: really implement this */ - sanyo_set_frequency(value); - val = sanyo_get(RADIO_TUNED); + set_frequency(value); + val = lv24020lp_get(RADIO_TUNED); break; case RADIO_MUTE: if (value) - tuner_sanyo_write_and(RADIO_CTRL3, ~AMUTE_L); + lv24020lp_write_and(RADIO_CTRL3, ~AMUTE_L); else - tuner_sanyo_write_or(RADIO_CTRL3, AMUTE_L); + lv24020lp_write_or(RADIO_CTRL3, AMUTE_L); break; case RADIO_REGION: - switch (value) - { - case REGION_EUROPE: - case REGION_JAPAN: - case REGION_KOREA: - tuner_sanyo_write_and(AUDIO_CTRL2, ~DEEMP); - break; - case REGION_US_CANADA: - tuner_sanyo_write_or(AUDIO_CTRL2, DEEMP); - break; - default: - val = -1; - } + { + if (lv24020lp_region_data[value]) + lv24020lp_write_or(AUDIO_CTRL2, DEEMP); + else + lv24020lp_write_and(AUDIO_CTRL2, ~DEEMP); break; + } case RADIO_FORCE_MONO: if (value) - tuner_sanyo_write_or(STEREO_CTRL, ST_M); + lv24020lp_write_or(STEREO_CTRL, ST_M); else - tuner_sanyo_write_and(STEREO_CTRL, ~ST_M); + lv24020lp_write_and(STEREO_CTRL, ~ST_M); break; default: @@ -861,45 +813,55 @@ int sanyo_set(int setting, int value) return val; } -int sanyo_get(int setting) +int lv24020lp_get(int setting) { int val = -1; switch(setting) { - case RADIO_ALL: - return tuner_sanyo_read(CTRL_STAT); - case RADIO_TUNED: /* TODO: really implement this */ - val = RSS_FS(tuner_sanyo_read(RADIO_STAT)) < 0x1f; + val = RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f; break; case RADIO_STEREO: - val = (tuner_sanyo_read(RADIO_STAT) & RSS_MS) != 0; + val = (lv24020lp_read(RADIO_STAT) & RSS_MS) != 0; break; case RADIO_PRESENT: + { + bool fmstatus = true; + + if (!(tuner_status & TUNER_PRESENCE_CHECKED)) + fmstatus = tuner_power(true); + val = (tuner_status & TUNER_PRESENT) != 0; + + if (!fmstatus) + tuner_power(false); break; + } /* tuner-specific debug info */ - case RADIO_REG_STAT: - return tuner_sanyo_read(RADIO_STAT); + case LV24020LP_CTRL_STAT: + return lv24020lp_read(CTRL_STAT); + + case LV24020LP_REG_STAT: + return lv24020lp_read(RADIO_STAT); - case RADIO_MSS_FM: + case LV24020LP_MSS_FM: return tuner_measure(MSS_FM, 1, 16); - case RADIO_MSS_IF: + case LV24020LP_MSS_IF: return tuner_measure(MSS_IF, 1000, 16); - case RADIO_MSS_SD: + case LV24020LP_MSS_SD: return tuner_measure(MSS_SD, 1000, 16); - case RADIO_IF_SET: + case LV24020LP_IF_SET: return if_set; - case RADIO_SD_SET: + case LV24020LP_SD_SET: return sd_set; } diff --git a/firmware/tuner_samsung.c b/firmware/drivers/tuner/s1a0903x01.c index 82934d7160..cdeba2b3b4 100644 --- a/firmware/tuner_samsung.c +++ b/firmware/drivers/tuner/s1a0903x01.c @@ -33,9 +33,10 @@ static int fm_in1; static int fm_in2; +static int fm_present = -1; /* unknown */ /* tuner abstraction layer: set something to the tuner */ -int samsung_set(int setting, int value) +int s1a0903x01_set(int setting, int value) { int val = 1; @@ -95,12 +96,13 @@ int samsung_set(int setting, int value) case RADIO_SCAN_FREQUENCY: /* Tune in and delay */ - samsung_set(RADIO_FREQUENCY, value); + s1a0903x01_set(RADIO_FREQUENCY, value); sleep(1); /* Start IF measurement */ - samsung_set(RADIO_IF_MEASUREMENT, 1); + fm_in1 |= 4; + fmradio_set(1, fm_in1); sleep(1); - val = samsung_get(RADIO_TUNED); + val = s1a0903x01_get(RADIO_TUNED); break; case RADIO_MUTE: @@ -108,20 +110,23 @@ int samsung_set(int setting, int value) fmradio_set(1, fm_in1); break; - case RADIO_IF_MEASUREMENT: + 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 RADIO_SENSITIVITY: + case S1A0903X01_SENSITIVITY: fm_in2 = (fm_in2 & 0xffff9fff) | ((value & 3) << 13); fmradio_set(2, fm_in2); break; - - case RADIO_FORCE_MONO: - fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4); - fmradio_set(2, fm_in2); - break; +#endif default: val = -1; } @@ -130,14 +135,27 @@ int samsung_set(int setting, int value) } /* tuner abstraction layer: read something from the tuner */ -int samsung_get(int setting) +int s1a0903x01_get(int setting) { int val = -1; switch(setting) { case RADIO_PRESENT: - fmradio_set(2, 0x140885); /* 5kHz, 7.2MHz crystal, test mode 1 */ - val = (fmradio_read(0) == 0x140885); + 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: @@ -148,6 +166,7 @@ int samsung_get(int setting) case RADIO_STEREO: val = fmradio_read(3); val = ((val & 0x100000) ? true : false); + break; } return val; } diff --git a/firmware/tuner_philips.c b/firmware/drivers/tuner/tea5767.c index 8520fdbae9..da7cdfb65a 100644 --- a/firmware/tuner_philips.c +++ b/firmware/drivers/tuner/tea5767.c @@ -23,13 +23,21 @@ #include <stdlib.h> #include "kernel.h" #include "tuner.h" /* tuner abstraction interface */ +#include "fmradio.h" #include "fmradio_i2c.h" /* physical interface driver */ #define I2C_ADR 0xC0 static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; +static void tea5767_set_clear(int byte, unsigned char bits, int set) +{ + write_bytes[byte] &= ~bits; + if (set) + write_bytes[byte] |= bits; +} + /* tuner abstraction layer: set something to the tuner */ -int philips_set(int setting, int value) +int tea5767_set(int setting, int value) { switch(setting) { @@ -44,7 +52,7 @@ int philips_set(int setting, int value) write_bytes[3] |= (1<<3) | (1<<1); #endif /* sleep / standby mode */ - write_bytes[3] &= ~(1<<6) | (value ? (1<<6) : 0); + tea5767_set_clear(3, (1<<6), value); break; case RADIO_FREQUENCY: @@ -56,38 +64,41 @@ int philips_set(int setting, int value) n = (4 * (value - 225000)) / 50000; #endif write_bytes[0] = (write_bytes[0] & 0xC0) | (n >> 8); - write_bytes[1] = n & 0xFF; + write_bytes[1] = n; } break; case RADIO_SCAN_FREQUENCY: - philips_set(RADIO_FREQUENCY, value); + tea5767_set(RADIO_FREQUENCY, value); sleep(HZ/30); - return philips_get(RADIO_TUNED); + return tea5767_get(RADIO_TUNED); case RADIO_MUTE: - write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0); + tea5767_set_clear(0, 0x80, value); break; - case RADIO_FORCE_MONO: - write_bytes[2] = (write_bytes[2] & 0xF7) | (value ? 0x08 : 0); - break; + case RADIO_REGION: + { + const struct tea5767_region_data *rd = + &tea5767_region_data[value]; - case RADIO_SET_DEEMPHASIS: - write_bytes[4] = (write_bytes[4] & ~(1<<6)) | (value ? (1<<6) : 0); + tea5767_set_clear(4, (1<<6), rd->deemphasis); + tea5767_set_clear(3, (1<<5), rd->band); + break; + } + case RADIO_FORCE_MONO: + tea5767_set_clear(2, 0x08, value); break; - - case RADIO_SET_BAND: - write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0); default: return -1; } + fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); return 1; } /* tuner abstraction layer: read something from the tuner */ -int philips_get(int setting) +int tea5767_get(int setting) { unsigned char read_bytes[5]; int val = -1; /* default for unsupported query */ @@ -113,10 +124,11 @@ int philips_get(int setting) val = read_bytes[2] >> 7; break; } + return val; } -void philips_dbg_info(struct philips_dbg_info *info) +void tea5767_dbg_info(struct tea5767_dbg_info *info) { fmradio_i2c_read(I2C_ADR, info->read_regs, 5); memcpy(info->write_regs, write_bytes, 5); diff --git a/firmware/export/config.h b/firmware/export/config.h index 86e27d0031..056b9857bc 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -245,6 +245,11 @@ #define CONFIG_REMOTE_DEFAULT_ICON_WIDTH 6 #endif +#if (CONFIG_TUNER & (CONFIG_TUNER - 1)) != 0 +/* Multiple possible tuners */ +#define CONFIG_TUNER_MULTI +#endif + /* Enable the directory cache and tagcache in RAM if we have * plenty of RAM. Both features can be enabled independently. */ #if ((defined(MEMORYSIZE) && (MEMORYSIZE > 8)) || MEM > 8) && \ diff --git a/firmware/export/hwcompat.h b/firmware/export/hwcompat.h index bffb76e3ef..bebca68a6c 100644 --- a/firmware/export/hwcompat.h +++ b/firmware/export/hwcompat.h @@ -46,4 +46,11 @@ bool is_new_player(void); #endif +#ifdef CONFIG_TUNER_MULTI +static inline int tuner_detect_type(void) +{ + return (HW_MASK & TUNER_MODEL) ? TEA5767 : S1A0903X01; +} +#endif + #endif /* HWCOMPAT_H */ diff --git a/firmware/export/lv24020lp.h b/firmware/export/lv24020lp.h new file mode 100644 index 0000000000..0fc39b18df --- /dev/null +++ b/firmware/export/lv24020lp.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Tuner header for the Sanyo LV24020LP + * + * Copyright (C) 2007 Michael Sevakis + * + * 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. + * + ****************************************************************************/ + +#ifndef _LV24020LP_H_ +#define _LV24020LP_H_ + +/* Define additional tuner messages here */ +#define HAVE_RADIO_REGION + +#define LV24020LP_CTRL_STAT (RADIO_GET_CHIP_FIRST+0) +#define LV24020LP_REG_STAT (RADIO_GET_CHIP_FIRST+1) +#define LV24020LP_MSS_FM (RADIO_GET_CHIP_FIRST+2) +#define LV24020LP_MSS_IF (RADIO_GET_CHIP_FIRST+3) +#define LV24020LP_MSS_SD (RADIO_GET_CHIP_FIRST+4) +#define LV24020LP_IF_SET (RADIO_GET_CHIP_FIRST+5) +#define LV24020LP_SD_SET (RADIO_GET_CHIP_FIRST+6) + +struct lv24020lp_region_data +{ + unsigned char deemphasis; +} __attribute__((packed)); + +const unsigned char lv24020lp_region_data[TUNER_NUM_REGIONS]; + +int lv24020lp_set(int setting, int value); +int lv24020lp_get(int setting); +void lv24020lp_power(bool status); + +#ifndef CONFIG_TUNER_MULTI +#define tuner_set lv24020lp_set +#define tuner_get lv24020lp_get +#endif + +#endif /* _LV24020LP_H_ */ diff --git a/firmware/export/power.h b/firmware/export/power.h index cafd6f87c8..8ecff6c51e 100644 --- a/firmware/export/power.h +++ b/firmware/export/power.h @@ -48,8 +48,8 @@ bool spdif_powered(void); #endif #if CONFIG_TUNER -extern bool radio_power(bool status); -extern bool radio_powered(void); +extern bool tuner_power(bool status); +extern bool tuner_powered(void); #endif #endif diff --git a/firmware/export/s1a0903x01.h b/firmware/export/s1a0903x01.h new file mode 100644 index 0000000000..bf497628b7 --- /dev/null +++ b/firmware/export/s1a0903x01.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Tuner header for the Samsung S1A0903X01 + * + * Copyright (C) 2007 Michael Sevakis + * + * 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. + * + ****************************************************************************/ + +#ifndef _S1A0903X01_H_ +#define _S1A0903X01_H_ + +/* Define additional tuner messages here */ +#define HAVE_RADIO_MUTE_TIMEOUT + +#if 0 +#define S1A0903X01_IF_MEASUREMENT (RADIO_SET_CHIP_FIRST+0) +#define S1A0903X01_SENSITIVITY (RADIO_SET_CHIP_FIRST+1) +#endif + +int s1a0903x01_set(int setting, int value); +int s1a0903x01_get(int setting); + +#ifndef CONFIG_TUNER_MULTI +#define tuner_set s1a0903x01_get +#define tuner_get s1a0903x01_set +#endif + +#endif /* _S1A0903X01_H_ */ diff --git a/firmware/export/tea5767.h b/firmware/export/tea5767.h new file mode 100644 index 0000000000..dfa6149f20 --- /dev/null +++ b/firmware/export/tea5767.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * Tuner header for the Philips TEA5767 + * + * Copyright (C) 2007 Michael Sevakis + * + * 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. + * + ****************************************************************************/ + +#ifndef _TEA5767_H_ +#define _TEA5767_H_ + +#define HAVE_RADIO_REGION +#define HAVE_RADIO_MUTE_TIMEOUT + +struct tea5767_region_data +{ + unsigned char deemphasis; /* 0: 50us, 1: 75us */ + unsigned char band; /* 0: europe, 1: japan (BL in TEA spec)*/ +} __attribute__((packed)); + +const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS]; + +struct tea5767_dbg_info +{ + unsigned char read_regs[5]; + unsigned char write_regs[5]; +}; + +int tea5767_set(int setting, int value); +int tea5767_get(int setting); +void tea5767_dbg_info(struct tea5767_dbg_info *info); + +#ifndef CONFIG_TUNER_MULTI +#define tuner_set tea5767_set +#define tuner_get tea5767_get +#endif + +#endif /* _TEA5767_H_ */ diff --git a/firmware/export/tuner.h b/firmware/export/tuner.h index 9f6d29f697..cf18102744 100644 --- a/firmware/export/tuner.h +++ b/firmware/export/tuner.h @@ -22,101 +22,112 @@ #include "hwcompat.h" -/* settings to the tuner layer */ -#define RADIO_ALL -1 /* debug */ -#define RADIO_SLEEP 0 -#define RADIO_FREQUENCY 1 -#define RADIO_MUTE 2 -#define RADIO_IF_MEASUREMENT 3 -#define RADIO_SENSITIVITY 4 -#define RADIO_FORCE_MONO 5 -#define RADIO_SCAN_FREQUENCY 6 -#if (CONFIG_TUNER & TEA5767) -#define RADIO_SET_DEEMPHASIS 7 -#define RADIO_SET_BAND 8 -#endif -#if (CONFIG_TUNER & LV24020LP) -#define RADIO_REGION 9 /* to be used for all tuners */ -#define RADIO_REG_STAT 100 -#define RADIO_MSS_FM 101 -#define RADIO_MSS_IF 102 -#define RADIO_MSS_SD 103 -#define RADIO_IF_SET 104 -#define RADIO_SD_SET 105 -#endif -/* readback from the tuner layer */ -#define RADIO_PRESENT 0 -#define RADIO_TUNED 1 -#define RADIO_STEREO 2 +/** Settings to the tuner layer **/ +enum +{ + RADIO_ALL = -1, /* debug */ + RADIO_SLEEP, + RADIO_FREQUENCY, + RADIO_MUTE, + RADIO_FORCE_MONO, + RADIO_SCAN_FREQUENCY, + + /* Put new general-purpose settings above this line */ + __RADIO_SET_STANDARD_LAST +}; + +/** Readback from the tuner layer **/ +enum +{ + RADIO_PRESENT = 0, + RADIO_TUNED, + RADIO_STEREO, + + /* Put new general-purpose readback values above this line */ + __RADIO_GET_STANDARD_LAST +}; + +/** Tuner regions **/ + +/* Basic region information */ +enum +{ + REGION_EUROPE = 0, + REGION_US_CANADA, + REGION_JAPAN, + REGION_KOREA, + + /* Add new regions above this line */ + TUNER_NUM_REGIONS +}; -#define REGION_EUROPE 0 -#define REGION_US_CANADA 1 -#define REGION_JAPAN 2 -#define REGION_KOREA 3 +struct fm_region_data +{ + int freq_min; + int freq_max; + int freq_step; +}; + +extern const struct fm_region_data fm_region_data[TUNER_NUM_REGIONS]; #if CONFIG_TUNER #ifdef SIMULATOR -int radio_set(int setting, int value); -int radio_get(int setting); +int tuner_set(int setting, int value); +int tuner_get(int setting); #else -#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 -#elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ -#define radio_set _radio_set -#define radio_get _radio_get -int (*_radio_set)(int setting, int value); -int (*_radio_get)(int setting); -#endif /* CONFIG_TUNER == */ -#endif /* SIMULATOR */ -#if (CONFIG_TUNER & S1A0903X01) -int samsung_set(int setting, int value); -int samsung_get(int setting); -#endif /* CONFIG_TUNER & S1A0903X01 */ +#ifdef CONFIG_TUNER_MULTI +extern int (*tuner_set)(int setting, int value); +extern int (*tuner_get)(int setting); +#endif /* CONFIG_TUNER_MULTI */ +/** Sanyo LV24020LP **/ #if (CONFIG_TUNER & LV24020LP) -int sanyo_set(int setting, int value); -int sanyo_get(int setting); -#endif /* CONFIG_TUNER & LV24020LP */ +/* Sansa e200 Series */ +#include "lv24020lp.h" +#endif + +/** Samsung S1A0903X01 **/ +#if (CONFIG_TUNER & S1A0903X01) +/* Ondio FM, FM Recorder */ +#include "s1a0903x01.h" +#endif +/** Philips TEA5767 **/ #if (CONFIG_TUNER & TEA5767) -struct philips_dbg_info +/* Ondio FM, FM Recorder, Recorder V2, iRiver h100/h300, iAudio x5 */ +#include "tea5767.h" +#endif + +#endif /* SIMULATOR */ + +/* Additional messages that get enumerated after tuner driver headers */ + +/* for tuner_set */ +enum { - unsigned char read_regs[5]; - unsigned char write_regs[5]; + __RADIO_SET_ADDITIONAL_START = __RADIO_SET_STANDARD_LAST-1, +#ifdef HAVE_RADIO_REGION + RADIO_REGION, +#endif + + RADIO_SET_CHIP_FIRST }; -int philips_set(int setting, int value); -int philips_get(int setting); -void philips_dbg_info(struct philips_dbg_info *info); -#endif /* CONFIG_TUNER & TEA5767 */ - -/* Just inline here since only radio screen needs this atm and - there's no tuner.c. */ -static inline void tuner_init(void) + +/* for tuner_get */ +enum { -#ifndef SIMULATOR -#if CONFIG_TUNER == (S1A0903X01 | TEA5767) - if (HW_MASK & TUNER_MODEL) - { - _radio_set = philips_set; - _radio_get = philips_get; - } - else - { - _radio_set = samsung_set; - _radio_get = samsung_get; - } -#endif -#endif -} + __RADIO_GET_ADDITIONAL_START = __RADIO_SET_STANDARD_LAST-1, + + RADIO_GET_CHIP_FIRST +}; + +/** **/ + +void tuner_init(void); +bool tuner_power(bool power); +bool tuner_powered(void); #endif /* #if CONFIG_TUNER */ diff --git a/firmware/target/arm/archos/av300/power-av300.c b/firmware/target/arm/archos/av300/power-av300.c index cfdce69b13..6cc8b4f7c7 100644 --- a/firmware/target/arm/archos/av300/power-av300.c +++ b/firmware/target/arm/archos/av300/power-av300.c @@ -84,12 +84,12 @@ void ide_power_enable(bool on) static bool powered = false; -bool radio_powered() +bool tuner_powered() { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/target/arm/iriver/h10/power-h10.c b/firmware/target/arm/iriver/h10/power-h10.c index 63eb2dc189..d0d3ce59d1 100644 --- a/firmware/target/arm/iriver/h10/power-h10.c +++ b/firmware/target/arm/iriver/h10/power-h10.c @@ -40,12 +40,12 @@ bool charger_enabled; static bool powered = false; -bool radio_powered() +bool tuner_powered() { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c b/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c index 4e4f585298..dfdcb1d27a 100644 --- a/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c +++ b/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c @@ -30,12 +30,12 @@ static bool powered = false; -bool radio_powered(void) +bool tuner_powered(void) { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/target/arm/sandisk/sansa-e200/power-e200.c b/firmware/target/arm/sandisk/sansa-e200/power-e200.c index dfa4211a91..002dcb8407 100644 --- a/firmware/target/arm/sandisk/sansa-e200/power-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/power-e200.c @@ -21,6 +21,7 @@ #include "system.h" #include "cpu.h" #include "i2c-pp.h" +#include "tuner.h" void power_init(void) { @@ -61,3 +62,60 @@ void ide_power_enable(bool on) { (void)on; } + +/** Tuner **/ +static bool powered = false; + +bool tuner_power(bool status) +{ + bool old_status = powered; + + if (status != old_status) + { + if (status) + { + /* init mystery amplification device */ + outl(inl(0x70000084) | 0x1, 0x70000084); + udelay(5); + + /* When power up, host should initialize the 3-wire bus + in host read mode: */ + + /* 1. Set direction of the DATA-line to input-mode. */ + GPIOH_OUTPUT_EN &= ~(1 << 5); + GPIOH_ENABLE |= (1 << 5); + + /* 2. Drive NR_W low */ + GPIOH_OUTPUT_VAL &= ~(1 << 3); + GPIOH_OUTPUT_EN |= (1 << 3); + GPIOH_ENABLE |= (1 << 3); + + /* 3. Drive CLOCK high */ + GPIOH_OUTPUT_VAL |= (1 << 4); + GPIOH_OUTPUT_EN |= (1 << 4); + GPIOH_ENABLE |= (1 << 4); + + lv24020lp_power(true); + } + else + { + lv24020lp_power(false); + + /* set all as inputs */ + GPIOH_OUTPUT_EN &= ~((1 << 5) | (1 << 3) | (1 << 4)); + GPIOH_ENABLE &= ~((1 << 5) | (1 << 3) | (1 << 4)); + + /* turn off mystery amplification device */ + outl(inl(0x70000084) & ~0x1, 0x70000084); + } + + powered = status; + } + + return old_status; +} + +bool tuner_powered(void) +{ + return powered; +} diff --git a/firmware/target/coldfire/iaudio/x5/power-x5.c b/firmware/target/coldfire/iaudio/x5/power-x5.c index c646570821..5c6c388a71 100644 --- a/firmware/target/coldfire/iaudio/x5/power-x5.c +++ b/firmware/target/coldfire/iaudio/x5/power-x5.c @@ -90,12 +90,12 @@ void ide_power_enable(bool on) static bool powered = false; -bool radio_powered() +bool tuner_powered() { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/target/coldfire/iriver/h100/power-h100.c b/firmware/target/coldfire/iriver/h100/power-h100.c index 943168967f..c1841264a2 100644 --- a/firmware/target/coldfire/iriver/h100/power-h100.c +++ b/firmware/target/coldfire/iriver/h100/power-h100.c @@ -29,12 +29,12 @@ static bool powered = false; -bool radio_powered(void) +bool tuner_powered(void) { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; diff --git a/firmware/target/coldfire/iriver/h300/power-h300.c b/firmware/target/coldfire/iriver/h300/power-h300.c index 5e57326c36..b687b29cba 100644 --- a/firmware/target/coldfire/iriver/h300/power-h300.c +++ b/firmware/target/coldfire/iriver/h300/power-h300.c @@ -29,12 +29,12 @@ static bool powered = false; -bool radio_powered(void) +bool tuner_powered(void) { return powered; } -bool radio_power(bool status) +bool tuner_power(bool status) { bool old_status = powered; powered = status; |