summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2005-08-13 17:32:15 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2005-08-13 17:32:15 +0000
commitcc5d96f8a93598fe48a9d8e3d9df3990ecaed023 (patch)
treeb43753544a93d1807be8a27de1478533cf219ce4
parent4af42510768f422e7f55e1f732fc36b5c3ee10a5 (diff)
downloadrockbox-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.c205
-rw-r--r--firmware/drivers/i2c-coldfire.c24
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;
}
}