diff options
| author | Bertrik Sikken <bertrik@sikken.nl> | 2010-06-16 20:29:08 +0000 |
|---|---|---|
| committer | Bertrik Sikken <bertrik@sikken.nl> | 2010-06-16 20:29:08 +0000 |
| commit | ff8e76e9e534dde1e6a57a84d49b89dad847cafd (patch) | |
| tree | 3fdbb6307e1c1350d13bb205a96e0a5d7df3ad01 /firmware/drivers | |
| parent | 60d5f5050b00e05385cbe55a9d639a56e013ff3f (diff) | |
| download | rockbox-ff8e76e9e534dde1e6a57a84d49b89dad847cafd.zip rockbox-ff8e76e9e534dde1e6a57a84d49b89dad847cafd.tar.gz rockbox-ff8e76e9e534dde1e6a57a84d49b89dad847cafd.tar.bz2 rockbox-ff8e76e9e534dde1e6a57a84d49b89dad847cafd.tar.xz | |
The mystery FM chip in some Sansa Clip+ players has been identified as a RDA5802, so rename files and functions. Also fix several bugs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26871 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
| -rw-r--r-- | firmware/drivers/tuner/rda5802.c (renamed from firmware/drivers/tuner/fmclipplus.c) | 167 |
1 files changed, 86 insertions, 81 deletions
diff --git a/firmware/drivers/tuner/fmclipplus.c b/firmware/drivers/tuner/rda5802.c index 1922662..a505b6b 100644 --- a/firmware/drivers/tuner/fmclipplus.c +++ b/firmware/drivers/tuner/rda5802.c @@ -7,8 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Tuner "middleware" for unidentified Silicon Labs chip present in some - * Sansa Clip+ players + * Tuner "middleware" for RDA5802 chip present in some Sansa Clip+ players * * Copyright (C) 2010 Bertrik Sikken * Copyright (C) 2008 Nils Wallménius (si4700 code that this was based on) @@ -31,7 +30,7 @@ #include "fmradio.h" #include "fmradio_i2c.h" /* physical interface driver */ -#define SEEK_THRESHOLD 0x10 +#define SEEK_THRESHOLD 0x16 #define I2C_ADR 0x20 @@ -50,6 +49,7 @@ /* POWERCFG (0x2) */ #define POWERCFG_DMUTE (0x1 << 14) #define POWERCFG_MONO (0x1 << 13) +#define POWERCFG_SOFT_RESET (0x1 << 1) #define POWERCFG_ENABLE (0x1 << 0) /* CHANNEL (0x3) */ @@ -62,15 +62,20 @@ #define CHANNEL_BAND_875_1080 (0x0 << 2) /* tenth-megahertz */ #define CHANNEL_BAND_760_1080 (0x1 << 2) #define CHANNEL_BAND_760_900 (0x2 << 2) + #define CHANNEL_BAND_650_760 (0x3 << 2) #define CHANNEL_SPACE (0x3 << 0) #define CHANNEL_SPACEw(x) (((x) << 0) & CHANNEL_SPACE) #define CHANNEL_SPACEr(x) (((x) & CHANNEL_SPACE) >> 0) - #define CHANNEL_SPACE_200KHZ (0x0 << 0) - #define CHANNEL_SPACE_100KHZ (0x1 << 0) + #define CHANNEL_SPACE_100KHZ (0x0 << 0) + #define CHANNEL_SPACE_200KHZ (0x1 << 0) #define CHANNEL_SPACE_50KHZ (0x2 << 0) /* SYSCONFIG1 (0x4) */ #define SYSCONFIG1_DE (0x1 << 11) + #define SYSCONFIG1_SMUTE (0x1 << 9) + +/* SYSCONFIG2 (0x5) */ +#define SYSCONFIG2_VOLUME (0xF << 0) /* READCHAN (0xA) */ #define READCHAN_READCHAN (0x3ff << 0) @@ -79,44 +84,39 @@ #define READCHAN_ST (0x1 << 10) /* STATUSRSSI (0xB) */ -#define STATUSRSSI_RSSI (0x3F << 10) - #define STATUSRSSI_RSSIr(x) (((x) & STATUSRSSI_RSSI) >> 10) -#define STATUSRSSI_AFCRL (0x1 << 8) +#define STATUSRSSI_RSSI (0x7F << 9) + #define STATUSRSSI_RSSIr(x) (((x) & STATUSRSSI_RSSI) >> 9) +#define STATUSRSSI_FM_TRUE (0x1 << 8) -static const uint16_t initvals[32] = { - 0x8110, 0x4580, 0xC401, 0x1B90, +static const uint16_t initvals[16] = { + 0x0000, 0x0000, 0xC401, 0x1B90, 0x0400, 0x866F, 0x8000, 0x4712, 0x5EC6, 0x0000, 0x406E, 0x2D80, - 0x5803, 0x5804, 0x5804, 0x5804, - - 0x0047, 0x9000, 0xF587, 0x0009, - 0x00F1, 0x41C0, 0x41E0, 0x506F, - 0x5592, 0x007D, 0x10A0, 0x0780, - 0x311D, 0x4006, 0x1F9B, 0x4C2B + 0x5803, 0x5804, 0x5804, 0x5804 }; static bool tuner_present = false; static int curr_frequency = 87500000; /* Current station frequency (HZ) */ -static uint16_t cache[32]; +static uint16_t cache[16]; /* reads <len> registers from radio at offset 0x0A into cache */ -static void fmclipplus_read(int len) +static void rda5802_read(int len) { int i; - unsigned char buf[64]; + unsigned char buf[128]; unsigned char *ptr = buf; uint16_t data; fmradio_i2c_read(I2C_ADR, buf, len * 2); for (i = 0; i < len; i++) { data = ptr[0] << 8 | ptr[1]; - cache[(i + READCHAN) & 0x1F] = data; + cache[READCHAN + i] = data; ptr += 2; } } /* writes <len> registers from cache to radio at offset 0x02 */ -static void fmclipplus_write(int len) +static void rda5802_write(int len) { int i; unsigned char buf[64]; @@ -124,78 +124,83 @@ static void fmclipplus_write(int len) uint16_t data; for (i = 0; i < len; i++) { - data = cache[(i + POWERCFG) & 0x1F]; + data = cache[POWERCFG + i]; *ptr++ = (data >> 8) & 0xFF; *ptr++ = data & 0xFF; } fmradio_i2c_write(I2C_ADR, buf, len * 2); } -static uint16_t fmclipplus_read_reg(int reg) +static uint16_t rda5802_read_reg(int reg) { - fmclipplus_read(((reg - READCHAN) & 0x1F) + 1); + rda5802_read((reg - READCHAN) + 1); return cache[reg]; } -static void fmclipplus_write_reg(int reg, uint16_t value) +static void rda5802_write_reg(int reg, uint16_t value) { cache[reg] = value; } -static void fmclipplus_write_cache(void) +static void rda5802_write_cache(void) +{ + rda5802_write(5); +} + +static void rda5802_write_masked(int reg, uint16_t bits, uint16_t mask) { - fmclipplus_write(5); + rda5802_write_reg(reg, (cache[reg] & ~mask) | (bits & mask)); } -static void fmclipplus_write_masked(int reg, uint16_t bits, uint16_t mask) +static void rda5802_write_clear(int reg, uint16_t mask) { - fmclipplus_write_reg(reg, (cache[reg] & ~mask) | (bits & mask)); + rda5802_write_reg(reg, cache[reg] & ~mask); } -static void fmclipplus_write_clear(int reg, uint16_t mask) +static void rda5802_write_set(int reg, uint16_t mask) { - fmclipplus_write_reg(reg, cache[reg] & ~mask); + rda5802_write_reg(reg, cache[reg] | mask); } -static void fmclipplus_sleep(int snooze) +static void rda5802_sleep(int snooze) { if (snooze) { - fmclipplus_write_masked(POWERCFG, 0, 0xFF); + rda5802_write_clear(POWERCFG, POWERCFG_ENABLE); } else { - fmclipplus_write_masked(POWERCFG, 1, 0xFF); + rda5802_write_set(POWERCFG, POWERCFG_ENABLE); } - fmclipplus_write_cache(); + rda5802_write_cache(); } -bool fmclipplus_detect(void) +bool rda5802_detect(void) { - return ((fmclipplus_read_reg(IDENT) & 0xFF00) == 0x5800); + return ((rda5802_read_reg(IDENT) & 0xFF00) == 0x5800); } -void fmclipplus_init(void) +void rda5802_init(void) { - if (fmclipplus_detect()) { + if (rda5802_detect()) { tuner_present = true; - // send pre-initialisation value - fmclipplus_write_reg(POWERCFG, 0x200); - fmclipplus_write(2); - sleep(HZ * 10 / 100); + // soft-reset + rda5802_write_reg(POWERCFG, POWERCFG_SOFT_RESET); + rda5802_write(1); + sleep(HZ * 10 / 1000); // write initialisation values memcpy(cache, initvals, sizeof(cache)); - fmclipplus_write(32); + rda5802_write(16); sleep(HZ * 70 / 1000); } } -static void fmclipplus_set_frequency(int freq) +static void rda5802_set_frequency(int freq) { int i; + uint16_t readchan; /* check BAND and spacings */ - fmclipplus_read_reg(STATUSRSSI); int start = CHANNEL_BANDr(cache[CHANNEL]) & 1 ? 76000000 : 87000000; int chan = (freq - start) / 50000; @@ -203,92 +208,92 @@ static void fmclipplus_set_frequency(int freq) for (i = 0; i < 5; i++) { /* tune and wait a bit */ - fmclipplus_write_masked(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE, + rda5802_write_masked(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE, CHANNEL_CHAN | CHANNEL_TUNE); - fmclipplus_write_cache(); + rda5802_write_cache(); sleep(HZ * 70 / 1000); - fmclipplus_write_clear(CHANNEL, CHANNEL_TUNE); - fmclipplus_write_cache(); + rda5802_write_clear(CHANNEL, CHANNEL_TUNE); + rda5802_write_cache(); /* check if tuning was successful */ - fmclipplus_read_reg(STATUSRSSI); - if (cache[READCHAN] & READCHAN_STC) { - if (READCHAN_READCHANr(cache[READCHAN]) == chan) { + readchan = rda5802_read_reg(READCHAN); + if (readchan & READCHAN_STC) { + if (READCHAN_READCHANr(readchan) == chan) { break; } } } } -static int fmclipplus_tuned(void) +static int rda5802_tuned(void) { /* Primitive tuning check: sufficient level and AFC not railed */ - uint16_t status = fmclipplus_read_reg(STATUSRSSI); + uint16_t status = rda5802_read_reg(STATUSRSSI); if (STATUSRSSI_RSSIr(status) >= SEEK_THRESHOLD && - (status & STATUSRSSI_AFCRL) == 0) { + (status & STATUSRSSI_FM_TRUE)) { return 1; } return 0; } -static void fmclipplus_set_region(int region) +static void rda5802_set_region(int region) { - const struct fmclipplus_region_data *rd = &fmclipplus_region_data[region]; + const struct rda5802_region_data *rd = &rda5802_region_data[region]; uint16_t bandspacing = CHANNEL_BANDw(rd->band) | CHANNEL_SPACEw(CHANNEL_SPACE_50KHZ); uint16_t oldbs = cache[CHANNEL] & (CHANNEL_BAND | CHANNEL_SPACE); - fmclipplus_write_masked(SYSCONFIG1, rd->deemphasis ? SYSCONFIG1_DE : 0, + rda5802_write_masked(SYSCONFIG1, rd->deemphasis ? SYSCONFIG1_DE : 0, SYSCONFIG1_DE); - fmclipplus_write_masked(CHANNEL, bandspacing, CHANNEL_BAND | CHANNEL_SPACE); - fmclipplus_write_cache(); + rda5802_write_masked(CHANNEL, bandspacing, CHANNEL_BAND | CHANNEL_SPACE); + rda5802_write_cache(); /* Retune if this region change would change the channel number. */ if (oldbs != bandspacing) { - fmclipplus_set_frequency(curr_frequency); + rda5802_set_frequency(curr_frequency); } } -static bool fmclipplus_st(void) +static bool rda5802_st(void) { - return (fmclipplus_read_reg(READCHAN) & READCHAN_ST); + return (rda5802_read_reg(READCHAN) & READCHAN_ST); } /* tuner abstraction layer: set something to the tuner */ -int fmclipplus_set(int setting, int value) +int rda5802_set(int setting, int value) { switch (setting) { case RADIO_SLEEP: if (value != 2) { - fmclipplus_sleep(value); + rda5802_sleep(value); } break; case RADIO_FREQUENCY: - fmclipplus_set_frequency(value); + rda5802_set_frequency(value); break; case RADIO_SCAN_FREQUENCY: - fmclipplus_set_frequency(value); - return fmclipplus_tuned(); + rda5802_set_frequency(value); + return rda5802_tuned(); case RADIO_MUTE: - fmclipplus_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE, + rda5802_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE, POWERCFG_DMUTE); - fmclipplus_write_masked(SYSCONFIG1, (3 << 9), (3 << 9)); - fmclipplus_write_masked(SYSCONFIG2, (0xF << 0), (0xF << 0)); - fmclipplus_write_cache(); + rda5802_write_masked(SYSCONFIG1, (3 << 9), (3 << 9)); + rda5802_write_set(SYSCONFIG2, SYSCONFIG2_VOLUME); + rda5802_write_cache(); break; case RADIO_REGION: - fmclipplus_set_region(value); + rda5802_set_region(value); break; case RADIO_FORCE_MONO: - fmclipplus_write_masked(POWERCFG, value ? POWERCFG_MONO : 0, + rda5802_write_masked(POWERCFG, value ? POWERCFG_MONO : 0, POWERCFG_MONO); - fmclipplus_write_cache(); + rda5802_write_cache(); break; default: @@ -299,7 +304,7 @@ int fmclipplus_set(int setting, int value) } /* tuner abstraction layer: read something from the tuner */ -int fmclipplus_get(int setting) +int rda5802_get(int setting) { int val = -1; /* default for unsupported query */ @@ -309,20 +314,20 @@ int fmclipplus_get(int setting) break; case RADIO_TUNED: - val = fmclipplus_tuned(); + val = rda5802_tuned(); break; case RADIO_STEREO: - val = fmclipplus_st(); + val = rda5802_st(); break; } return val; } -void fmclipplus_dbg_info(struct fmclipplus_dbg_info *nfo) +void rda5802_dbg_info(struct rda5802_dbg_info *nfo) { - fmclipplus_read(32); + rda5802_read(6); memcpy(nfo->regs, cache, sizeof (nfo->regs)); } |