diff options
| author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-17 23:24:18 +0000 |
|---|---|---|
| committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-17 23:24:18 +0000 |
| commit | 4adf929a90e1cc7bc559a69193a505166ddaba1b (patch) | |
| tree | a436c69572d55459f2f5e46b282a2ef15fb04d0f | |
| parent | ca45869a8866756c5c11cba307a7ff62566afb22 (diff) | |
| download | rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.zip rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.tar.gz rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.tar.bz2 rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.tar.xz | |
Philips tuner supported
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5300 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | firmware/drivers/fmradio_i2c.c | 179 | ||||
| -rw-r--r-- | firmware/export/fmradio_i2c.h | 4 | ||||
| -rw-r--r-- | firmware/tuner_philips.c | 25 |
3 files changed, 197 insertions, 11 deletions
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 93c5d2f..d503980 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c @@ -8,7 +8,7 @@ * $Id$ * Physical interface of the Philips TEA5767 in Archos Ondio * - * Copyright (C) 2004 by Jörg Hohensohn + * Copyright (C) 2002 by 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. @@ -26,16 +26,181 @@ #ifdef CONFIG_TUNER -/* reads 5 byte */ -void fmradio_i2c_read(unsigned char* p_data) + +/* cute little functions, atomic read-modify-write */ +/* SDA is PB4 */ +#define SDA_LO and_b(~0x10, &PBDRL) +#define SDA_HI or_b(0x10, &PBDRL) +#define SDA_INPUT and_b(~0x10, &PBIORL) +#define SDA_OUTPUT or_b(0x10, &PBIORL) +#define SDA (PBDR & 0x0010) + +/* SCL is PB1 */ +#define SCL_INPUT and_b(~0x02, &PBIORL) +#define SCL_OUTPUT or_b(0x02, &PBIORL) +#define SCL_LO and_b(~0x02, &PBDRL) +#define SCL_HI or_b(0x02, &PBDRL) +#define SCL (PBDR & 0x0002) + +/* arbitrary delay loop */ +#define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0) + + +static void fmradio_i2c_start(void) +{ + SDA_OUTPUT; + SDA_HI; + SCL_HI; + SDA_LO; + DELAY; + SCL_LO; +} + +static void fmradio_i2c_stop(void) +{ + SDA_LO; + SCL_HI; + DELAY; + SDA_HI; +} + + +static void fmradio_i2c_ack(int bit) +{ + /* Here's the deal. The slave is slow, and sometimes needs to wait + before it can receive the acknowledge. Therefore it forces the clock + low until it is ready. We need to poll the clock line until it goes + high before we release the ack. */ + + SCL_LO; /* Set the clock low */ + if ( bit ) + { + SDA_HI; + } + else + { + SDA_LO; + } + + SCL_INPUT; /* Set the clock to input */ + while(!SCL) /* and wait for the slave to release it */ + sleep_thread(); + wake_up_thread(); + + DELAY; + SCL_OUTPUT; + SCL_LO; +} + +static int fmradio_i2c_getack(void) { - (void)p_data; + int ret = 1; + + /* Here's the deal. The slave is slow, and sometimes needs to wait + before it can send the acknowledge. Therefore it forces the clock + low until it is ready. We need to poll the clock line until it goes + high before we read the ack. */ + + SDA_INPUT; /* And set to input */ + SCL_INPUT; /* Set the clock to input */ + while(!SCL) /* and wait for the slave to release it */ + sleep_thread(); + wake_up_thread(); + + if (SDA) + /* ack failed */ + ret = 0; + + SCL_OUTPUT; + SCL_LO; + SDA_HI; + SDA_OUTPUT; + return ret; +} + +static void fmradio_i2c_outb(unsigned char byte) +{ + int i; + + /* clock out each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) { + if ( i & byte ) + { + SDA_HI; + } + else + { + SDA_LO; + } + SCL_HI; + SCL_LO; + } + + SDA_HI; +} + +static unsigned char fmradio_i2c_inb(int ack) +{ + int i; + unsigned char byte = 0; + + /* clock in each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) { + SDA_INPUT; /* And set to input */ + SCL_HI; + if ( SDA ) + byte |= i; + SCL_LO; + SDA_OUTPUT; + } + + fmradio_i2c_ack(ack); + + return byte; +} + +int fmradio_i2c_write(int address, const unsigned char* buf, int count) +{ + int i,x=0; + + fmradio_i2c_start(); + fmradio_i2c_outb(address & 0xfe); + if (fmradio_i2c_getack()) + { + for (i=0; i<count; i++) + { + fmradio_i2c_outb(buf[i]); + if (!fmradio_i2c_getack()) + { + x=-2; + break; + } + } + } + else + { + debugf("fmradio_i2c_write() - no ack\n"); + x=-1; + } + fmradio_i2c_stop(); + return x; } -/* writes 5 bytes */ -void fmradio_i2c_set(const unsigned char* p_data) +int fmradio_i2c_read(int address, unsigned char* buf, int count) { - (void)p_data; + int i,x=0; + + fmradio_i2c_start(); + fmradio_i2c_outb(address | 1); + if (fmradio_i2c_getack()) { + for (i=0; i<count; i++) { + buf[i] = fmradio_i2c_inb(0); + } + } + else + x=-1; + fmradio_i2c_stop(); + return x; } #endif diff --git a/firmware/export/fmradio_i2c.h b/firmware/export/fmradio_i2c.h index 06b7f9f..b7007a8 100644 --- a/firmware/export/fmradio_i2c.h +++ b/firmware/export/fmradio_i2c.h @@ -20,7 +20,7 @@ #ifndef FMRADIO_I2C_H #define FMRADIO_I2C_H -void fmradio_i2c_read(unsigned char* p_data); /* reads 5 byte */ -void fmradio_i2c_set(const unsigned char* p_data); /* writes 5 bytes */ +int fmradio_i2c_write(int address, const unsigned char* buf, int count); +int fmradio_i2c_read(int address, unsigned char* buf, int count); #endif diff --git a/firmware/tuner_philips.c b/firmware/tuner_philips.c index 50559af..e63d063 100644 --- a/firmware/tuner_philips.c +++ b/firmware/tuner_philips.c @@ -19,10 +19,12 @@ ****************************************************************************/ #include <stdbool.h> +#include <string.h> #include "tuner.h" /* tuner abstraction interface */ #include "fmradio_i2c.h" /* physical interface driver */ -/* FIXME: this is just a dummy */ +#define I2C_ADR 0xC0 +static unsigned char write_bytes[5]; /* tuner abstraction layer: set something to the tuner */ void philips_set(int setting, int value) @@ -31,12 +33,22 @@ void philips_set(int setting, int value) switch(setting) { case RADIO_INIT: + memset(write_bytes, 0, sizeof(write_bytes)); break; case RADIO_FREQUENCY: + { + int n; + n = (4 * (value - 225000)) / 50000; + write_bytes[0] = (write_bytes[0] & 0xC0) | (n >> 8); + write_bytes[1] = n & 0xFF; + fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); + } break; case RADIO_MUTE: + write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0); + fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); break; case RADIO_IF_MEASUREMENT: @@ -46,6 +58,8 @@ void philips_set(int setting, int value) break; case RADIO_FORCE_MONO: + write_bytes[2] = (write_bytes[2] & 0xF7) | (value ? 0x08 : 0); + fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); break; } } @@ -53,17 +67,24 @@ void philips_set(int setting, int value) /* tuner abstraction layer: read something from the tuner */ int philips_get(int setting) { + unsigned char read_bytes[5]; int val = -1; + + fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes)); + switch(setting) { case RADIO_PRESENT: - val = 0; /* false */ + val = 1; /* true */ break; case RADIO_IF_MEASURED: + val = read_bytes[2] & 0x7F; + val = 1070 + (val-55)/2; break; case RADIO_STEREO: + val = read_bytes[2] >> 7; break; } return val; |