summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorBertrik Sikken <bertrik@sikken.nl>2010-06-16 20:29:08 +0000
committerBertrik Sikken <bertrik@sikken.nl>2010-06-16 20:29:08 +0000
commitff8e76e9e534dde1e6a57a84d49b89dad847cafd (patch)
tree3fdbb6307e1c1350d13bb205a96e0a5d7df3ad01 /firmware/drivers
parent60d5f5050b00e05385cbe55a9d639a56e013ff3f (diff)
downloadrockbox-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));
}