diff options
| author | Linus Nielsen Feltzing <linus@haxx.se> | 2005-08-13 17:32:15 +0000 |
|---|---|---|
| committer | Linus Nielsen Feltzing <linus@haxx.se> | 2005-08-13 17:32:15 +0000 |
| commit | cc5d96f8a93598fe48a9d8e3d9df3990ecaed023 (patch) | |
| tree | b43753544a93d1807be8a27de1478533cf219ce4 | |
| parent | 4af42510768f422e7f55e1f732fc36b5c3ee10a5 (diff) | |
| download | rockbox-cc5d96f8a93598fe48a9d8e3d9df3990ecaed023.zip rockbox-cc5d96f8a93598fe48a9d8e3d9df3990ecaed023.tar.gz rockbox-cc5d96f8a93598fe48a9d8e3d9df3990ecaed023.tar.bz2 rockbox-cc5d96f8a93598fe48a9d8e3d9df3990ecaed023.tar.xz | |
The iriver FM radio I2C cannot use the I2C controller, so we do the good old bitbanging instead
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7316 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | firmware/drivers/fmradio_i2c.c | 205 | ||||
| -rw-r--r-- | firmware/drivers/i2c-coldfire.c | 24 |
2 files changed, 212 insertions, 17 deletions
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index d503980..e7d5904 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c @@ -17,16 +17,210 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "lcd.h" -#include "sh7034.h" +#include "config.h" +#include "cpu.h" #include "kernel.h" #include "thread.h" -#include "debug.h" +#include "logf.h" #include "system.h" +#include "string.h" -#ifdef CONFIG_TUNER +#if (CONFIG_TUNER == TEA5767) +#if (CONFIG_I2C == I2C_COLDFIRE) +/* cute little functions, atomic read-modify-write */ +/* SDA is GPIO1,23 */ + +#define SDA_LO and_l(~0x00800000, &GPIO1_OUT) // and_b(~0x10, &PBDRL) +#define SDA_HI or_l( 0x00800000, &GPIO1_OUT) // or_b( 0x10, &PBDRL) +#define SDA_INPUT and_l(~0x00800000, &GPIO1_ENABLE) // and_b(~0x10, &PBIORL) +#define SDA_OUTPUT or_l( 0x00800000, &GPIO1_ENABLE) // or_b( 0x10, &PBIORL) +#define SDA ( 0x00800000 & GPIO1_READ) // (PBDR & 0x0010) + +/* SCL is GPIO, 3 */ +#define SCL_INPUT and_l(~0x00000008, &GPIO_ENABLE) // and_b(~0x02, &PBIORL) +#define SCL_OUTPUT or_l( 0x00000008, &GPIO_ENABLE) // or_b( 0x02, &PBIORL) +#define SCL_LO and_l(~0x00000008, &GPIO_OUT) // and_b(~0x02, &PBDRL) +#define SCL_HI or_l( 0x00000008, &GPIO_OUT) // or_b( 0x02, &PBDRL) +#define SCL ( 0x00000008 & GPIO_READ) // (PBDR & 0x0002) + +/* delay loop to achieve 400kHz at 120MHz CPU frequency */ +#define DELAY do { int _x; for(_x=0;_x<22;_x++);} while(0) + + +static void fmradio_i2c_start(void) +{ + SDA_OUTPUT; + SCL_OUTPUT; + SDA_HI; + SCL_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; +} + +static void fmradio_i2c_stop(void) +{ + SDA_LO; + SCL_HI; + DELAY; + SDA_HI; +} + + +static void fmradio_i2c_ack(void) +{ + /* 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. + + In their infinite wisdom, iriver didn't pull up the SCL line, so + we have to drive the SCL high repeatedly to simulate a pullup. */ + + SCL_LO; /* Set the clock low */ + SDA_LO; + + SCL_INPUT; /* Set the clock to input */ + while(!SCL) /* and wait for the slave to release it */ + { + SCL_OUTPUT; /* Set the clock to output */ + SCL_HI; + SCL_INPUT; /* Set the clock to input */ + DELAY; + } + + DELAY; + SCL_OUTPUT; + SCL_LO; +} + +static int fmradio_i2c_getack(void) +{ + 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. + + In their infinite wisdom, iriver didn't pull up the SCL line, so + we have to drive the SCL high repeatedly to simulate a pullup. */ + + SDA_INPUT; /* And set to input */ + SCL_INPUT; /* Set the clock to input */ + while(!SCL) /* and wait for the slave to release it */ + { + SCL_OUTPUT; /* Set the clock to output */ + SCL_HI; + SCL_INPUT; /* Set the clock to input */ + DELAY; + } + 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; + } + DELAY; + SCL_HI; + DELAY; + SCL_LO; + } + + SDA_HI; +} + +static unsigned char fmradio_i2c_inb(void) +{ + 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; + DELAY; + if ( SDA ) + byte |= i; + SCL_LO; + DELAY; + SDA_OUTPUT; + } + + fmradio_i2c_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 + { + logf("fmradio_i2c_write() - no ack\n"); + x=-1; + } + fmradio_i2c_stop(); + return x; +} + +int fmradio_i2c_read(int address, unsigned char* buf, int count) +{ + 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(); + } + } + else + x=-1; + fmradio_i2c_stop(); + return x; +} +#else /* cute little functions, atomic read-modify-write */ /* SDA is PB4 */ #define SDA_LO and_b(~0x10, &PBDRL) @@ -179,7 +373,7 @@ int fmradio_i2c_write(int address, const unsigned char* buf, int count) } else { - debugf("fmradio_i2c_write() - no ack\n"); + logf("fmradio_i2c_write() - no ack\n"); x=-1; } fmradio_i2c_stop(); @@ -204,3 +398,4 @@ int fmradio_i2c_read(int address, unsigned char* buf, int count) } #endif +#endif diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c index 7883851..aecd3a3 100644 --- a/firmware/drivers/i2c-coldfire.c +++ b/firmware/drivers/i2c-coldfire.c @@ -19,7 +19,7 @@ #include "cpu.h" #include "kernel.h" -#include "debug.h" +#include "logf.h" #include "system.h" #include "i2c-coldfire.h" @@ -37,28 +37,28 @@ static volatile unsigned char *i2c_get_addr(int device); void i2c_init(void) { + /* The FM chip has no pullup for SCL, so we have to bit-bang the + I2C for that one. */ + or_l(0x00800000, &GPIO1_OUT); + or_l(0x00000008, &GPIO_OUT); + or_l(0x00800000, &GPIO1_ENABLE); + or_l(0x00000008, &GPIO_ENABLE); + or_l(0x00800000, &GPIO1_FUNCTION); + or_l(0x00000008, &GPIO_FUNCTION); + /* I2C Clock divisor = 576 => 119.952 MHz / 2 / 576 = 104.125 kHz */ MFDR = 0x14; - MFDR2 = 0x14; #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) /* Audio Codec */ MBDR = 0; /* iRiver firmware does this */ MBCR = IEN; /* Enable interface */ - -#if 0 - /* FM Tuner */ - MBDR2 = 0; - MBCR2 = IEN; -#endif - #endif } void i2c_close(void) { MBCR = 0; - MBCR2 = 0; } /** @@ -77,7 +77,7 @@ int i2c_write(int device, unsigned char *buf, int count) rc = i2c_gen_start(device); if (rc < 0) { - DEBUGF("i2c: gen_start failed (d=%d)", device); + logf("i2c: gen_start failed (d=%d)", device); return rc*10 - 1; } @@ -86,7 +86,7 @@ int i2c_write(int device, unsigned char *buf, int count) rc = i2c_write_byte(device, buf[i]); if (rc < 0) { - DEBUGF("i2c: write failed at (d=%d,i=%d)", device, i); + logf("i2c: write failed at (d=%d,i=%d)", device, i); return rc*10 - 2; } } |