Index: firmware/target/arm/iriver/h10/fmradio_i2c-h10.c =================================================================== --- firmware/target/arm/iriver/h10/fmradio_i2c-h10.c (revision 16149) +++ firmware/target/arm/iriver/h10/fmradio_i2c-h10.c (working copy) @@ -29,148 +29,145 @@ #define SDA_LO_OUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x08) #define SDA (GPIOD_INPUT_VAL & 0x08) -#define SCL_INPUT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x10) -#define SCL_OUTPUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x10) -#define SCL_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x10) -#define SCL_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL,0x10) +#define SCL_OUTINIT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x10) +#define SCL_HI_IN GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN,0x10) +#define SCL_LO_OUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x10) #define SCL (GPIOD_INPUT_VAL & 0x10) -#define DELAY udelay(2) +#define DELAY fmradio_i2c_delay() +static void fmradio_i2c_delay(void) +{ + udelay(2); /* Ideally 2.5uS */ +} + +/* Set start condition */ static void fmradio_i2c_start(void) { - SCL_HI; - SCL_OUTPUT; + SCL_OUTINIT; + SCL_LO_OUT; + DELAY; SDA_HI_IN; SDA_OUTINIT; DELAY; + SCL_HI_IN; + DELAY; SDA_LO_OUT; DELAY; - SCL_LO; + SCL_LO_OUT; + DELAY; } +/* Set stop condition */ static void fmradio_i2c_stop(void) { - SDA_LO_OUT; - DELAY; - SCL_HI; - DELAY; - SDA_HI_IN; + SDA_LO_OUT; + DELAY; + SCL_HI_IN; + DELAY; + SDA_HI_IN; } /* Generate ACK or NACK */ static void fmradio_i2c_ack(bool nack) { - /* 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. */ - if (nack) SDA_HI_IN; else SDA_LO_OUT; + DELAY; - - SCL_HI; - do - { - SCL_OUTPUT; /* Set the clock to output */ - SCL_INPUT; /* Set the clock to input */ - DELAY; - } - while(!SCL); /* and wait for the slave to release it */ - - SCL_OUTPUT; - SCL_LO; + + SCL_HI_IN; + DELAY; + SCL_LO_OUT; + DELAY; } -static int fmradio_i2c_getack(void) +/* Get ack from receiver */ +static bool fmradio_i2c_getack(void) { - int ret = 1; + bool ret; - /* 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_HI_IN; /* sets to input */ + DELAY; + SCL_HI_IN; + DELAY; - 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. */ + ret = !SDA; /* ack failed if high */ - SDA_HI_IN; + SCL_LO_OUT; DELAY; - SCL_HI; /* set clock to high */ - do - { - SCL_OUTPUT; /* Set the clock to output */ - SCL_INPUT; /* Set the clock to input */ - DELAY; - } - while(!SCL); /* and wait for the slave to release it */ - - if (SDA) - ret = 0; /* ack failed */ - - SCL_OUTPUT; - SCL_LO; - return ret; } +/* Write a byte to slave receiver */ static void fmradio_i2c_outb(unsigned char byte) { - int i; + int i; - /* clock out each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) { - if ( i & byte ) - SDA_HI_IN; - else - SDA_LO_OUT; - DELAY; - SCL_HI; - DELAY; - SCL_LO; - } + /* clock out each bit, MSB first */ + for (i = 0x80; i; i >>= 1) + { + if (i & byte) + SDA_HI_IN; + else + SDA_LO_OUT; + DELAY; + + SCL_HI_IN; + DELAY; + SCL_LO_OUT; + + DELAY; + } } +/* Read a byte from slave transmitter */ static unsigned char fmradio_i2c_inb(void) { - int i; - unsigned char byte = 0; + int i; + unsigned char byte = 0; - SDA_HI_IN; - /* clock in each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) { - DELAY; - SCL_HI; - DELAY; - if ( SDA ) - byte |= i; - SCL_LO; - } + SDA_HI_IN; /* sets to input */ + DELAY; - return byte; + /* clock in each bit, MSB first */ + for (i = 0x80; i; i >>= 1) + { + do + { + SCL_HI_IN; + DELAY; + } + while (SCL == 0); /* wait for any SCL clock stretching */ + + if (SDA) + byte |= i; + + SCL_LO_OUT; + DELAY; + } + + return byte; } int fmradio_i2c_write(int address, const unsigned char* buf, int count) { - int i,x=0; + int i, x = 0; fmradio_i2c_start(); fmradio_i2c_outb(address & 0xfe); + if (fmradio_i2c_getack()) { - for (i=0; i0; i--) + for (i = count; i > 0; i--) { *buf++ = fmradio_i2c_inb(); fmradio_i2c_ack(i == 1); } } else - x=-1; + { + x = -1; + } + fmradio_i2c_stop(); return x; }