From b26e396436971b73c8a40f50121c404d643daf51 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 25 Oct 2006 06:10:22 +0000 Subject: [PATCH] Pinched pcf50606 i2c code used in iRiver players and adapted to x5. Boost ratios down as much as 100 percent for mp3 and 50 percent for vorbis. mp3 hardly ever boosts even with eq. Scrolling much sharper. Like a whole new player. The code can be used for both iRiver and x5 by just defining macros with the appropriate ports and bit numbers for each player. Probably will have a pcf50606-coldfire.c soon. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11330 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 1 - .../target/coldfire/iaudio/x5/pcf50606-x5.c | 548 +++++++++++++++--- .../target/coldfire/iaudio/x5/system-x5.c | 8 +- 3 files changed, 479 insertions(+), 78 deletions(-) diff --git a/firmware/SOURCES b/firmware/SOURCES index 05c03ce474..92a41cdead 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -239,7 +239,6 @@ target/arm/wmcodec-pp.c #ifdef IAUDIO_X5 target/coldfire/iaudio/x5/power-x5.c #ifndef SIMULATOR -drivers/generic_i2c.c target/coldfire/iaudio/x5/button-x5.c target/coldfire/iaudio/x5/lcd-as-x5.S target/coldfire/iaudio/x5/lcd-x5.c diff --git a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c index eaecc5bef6..59ecdb612c 100644 --- a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c +++ b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c @@ -28,92 +28,455 @@ #include "generic_i2c.h" #include "powermgmt.h" -void pcf50606_sda_output(void) +#define USE_ASM + +/* Data */ +#define SDA_BITNUM 12 /* SDA1/RXD1/GPIO44 */ +#define SDA_GPIO_READ GPIO1_READ /* MBAR2 + 0x0b0 */ +#define SDA_GPIO_OUT GPIO1_OUT /* MBAR2 + 0x0b4 */ +#define SDA_GPIO_ENABLE GPIO1_ENABLE /* MBAR2 + 0x0b8 */ +#define SDA_GPIO_FUNCTION GPIO1_FUNCTION /* MBAR2 + 0x0bc */ + +/* Clock */ +#define SCL_BITNUM 10 /* SCL1/TXD1/GPIO10 */ +#define SCL_GPIO_READ GPIO_READ /* MBAR2 + 0x000 */ +#define SCL_GPIO_OUT GPIO_OUT /* MBAR2 + 0x004 */ +#define SCL_GPIO_ENABLE GPIO_ENABLE /* MBAR2 + 0x008 */ +#define SCL_GPIO_FUNCTION GPIO_FUNCTION /* MBAR2 + 0x00c */ + +#define PCF50606_ADDR 0x10 +#define SCL_BIT (1ul << SCL_BITNUM) +#define SDA_BIT (1ul << SDA_BITNUM) + +#define SDA ( SDA_BIT & SDA_GPIO_READ) +#define SDA_LO_OUT or_l( SDA_BIT, &SDA_GPIO_ENABLE) +#define SDA_HI_IN and_l(~SDA_BIT, &SDA_GPIO_ENABLE) + +#define SCL ( SCL_BIT & SCL_GPIO_READ) +#define SCL_LO_OUT or_l( SCL_BIT, &SCL_GPIO_ENABLE) +#define SCL_HI_IN and_l(~SCL_BIT, &SCL_GPIO_ENABLE); while(!SCL); + +#define DELAY \ + asm ( \ + "move.l %[dly],%%d0 \n" \ + "1: \n" \ + "subq.l #1,%%d0 \n" \ + "bhi.s 1b \n" \ + : : [dly]"d"(i2c_delay) : "d0" ); + +static int i2c_delay IDATA_ATTR = 44; + +void pcf50606_i2c_recalc_delay(int cpu_clock) { - or_l( 0x00001000, &GPIO1_ENABLE); + i2c_delay = MAX(cpu_clock / (400000*2*3) - 7, 1); } -void pcf50606_sda_input(void) +inline void pcf50606_i2c_start(void) { - and_l(~0x00001000, &GPIO1_ENABLE); +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum], %%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_HI_IN; + SCL_HI_IN; + DELAY; + SDA_LO_OUT; + DELAY; + SCL_LO_OUT; +#endif } -void pcf50606_sda_lo(void) +inline void pcf50606_i2c_stop(void) { - and_l(~0x00001000, &GPIO1_OUT); +#ifdef USE_ASM + asm ( + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_LO_OUT; + SCL_HI_IN; + DELAY; + SDA_HI_IN; +#endif } -void pcf50606_sda_hi(void) +inline void pcf50606_i2c_ack(bool ack) { - or_l( 0x00001000, &GPIO1_OUT); +#ifdef USE_ASM + asm ( + "tst.b %[ack] \n" /* if (!ack) */ + "bne.s 1f \n" + + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + ".word 0x51fb \n" /* trapf.l : else */ + "1: \n" + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay), + [ack] "d"(ack) + : /* clobbers */ + "d0" + ); +#else + if(ack) + SDA_LO_OUT; + else + SDA_HI_IN; + + SCL_HI_IN; + + DELAY; + SCL_LO_OUT; +#endif } -int pcf50606_sda(void) +inline bool pcf50606_i2c_getack(void) { - return 0x00001000 & GPIO1_READ; + bool ret; + +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */ + "btst.l %[sdabnum],%%d0 \n" + "seq.b %[ret] \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + : /* outputs */ + [ret] "=&d"(ret) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [sdabnum] "i"(SDA_BITNUM), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_HI_IN; + DELAY; + SCL_HI_IN; + + ret = !SDA; + + SCL_LO_OUT; + DELAY; +#endif + return ret; } -void pcf50606_scl_output(void) +void pcf50606_i2c_outb(unsigned char byte) { - or_l( 0x00000400, &GPIO_ENABLE); -} +#ifdef USE_ASM + asm volatile ( + "moveq.l #24,%%d0 \n" /* byte <<= 24 */ + "lsl.l %%d0,%[byte] \n" + "moveq.l #8,%%d1 \n" /* i = 8 */ -void pcf50606_scl_input(void) -{ - and_l(~0x00000400, &GPIO_ENABLE); -} + "2: \n" /* do */ + "lsl.l #1,%[byte] \n" /* if ((byte <<= 1) carry) */ + "bcc.s 1f \n" -int pcf50606_scl(void) -{ - return 0x00000400 & GPIO_READ; -} + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + ".word 0x51fb \n" /* trapf.l; else */ + "1: \n" + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ -void pcf50606_scl_lo(void) -{ - and_l(~0x00000400, &GPIO_OUT); -} + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" -void pcf50606_scl_hi(void) -{ - pcf50606_scl_input(); - while(!pcf50606_scl()) + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "subq.l #1,%%d1 \n" /* i-- */ + "bne.s 2b \n" /* while (i != 0) */ + : /* outputs */ + [byte] "+d"(byte) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0", "d1" + ); +#else + 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_IN; + DELAY; + SCL_LO_OUT; } - or_l(0x0400, &GPIO_OUT); - pcf50606_scl_output(); +#endif } -void pcf50606_delay(void) +unsigned char pcf50606_i2c_inb(bool ack) { - do { int _x; for(_x=0;_x<32;_x++);} while(0); + unsigned char byte = 0; + +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "moveq.l #8,%%d1 \n" /* i = 8 */ + "clr.l %[byte] \n" /* byte = 0 */ + + "2: \n" /* do */ + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "lsl.l #1,%[byte] \n" /* byte <<= 1 */ + "move.l (%[sdard]),%%d0 \n" /* if (SDA) */ + "btst.l %[sdabnum],%%d0 \n" + "beq.s 1f \n" + "addq.l #1,%[byte] \n" /* byte++ */ + "1: \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "subq.l #1,%%d1 \n" /* i-- */ + "bne.s 2b \n" /* while (i != 0) */ + : /* outputs */ + [byte] "=&d"(byte) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [sdabnum] "i"(SDA_BITNUM), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0", "d1" + ); +#else + int i; + + /* clock in each bit, MSB first */ + SDA_HI_IN; + for ( i=0x80; i; i>>=1 ) + { + SCL_HI_IN; + DELAY; + if ( SDA ) + byte |= i; + SCL_LO_OUT; + DELAY; + } +#endif + + pcf50606_i2c_ack(ack); + + return byte; } -struct i2c_interface pcf50606_i2c = { - 0x10, /* Address */ +int pcf50606_i2c_write(int address, const unsigned char* buf, int count) +{ + int i,x=0; - /* Bit-banged interface definitions */ - pcf50606_scl_hi, /* Drive SCL high, might sleep on clk stretch */ - pcf50606_scl_lo, /* Drive SCL low */ - pcf50606_sda_hi, /* Drive SDA high */ - pcf50606_sda_lo, /* Drive SDA low */ - pcf50606_sda_input, /* Set SDA as input */ - pcf50606_sda_output, /* Set SDA as output */ - pcf50606_scl_input, /* Set SCL as input */ - pcf50606_scl_output, /* Set SCL as output */ - pcf50606_scl, /* Read SCL, returns 0 or nonzero */ - pcf50606_sda, /* Read SDA, returns 0 or nonzero */ - - pcf50606_delay, /* START SDA hold time (tHD:SDA) */ - pcf50606_delay, /* SDA hold time (tHD:DAT) */ - pcf50606_delay, /* SDA setup time (tSU:DAT) */ - pcf50606_delay, /* STOP setup time (tSU:STO) */ - pcf50606_delay, /* Rep. START setup time (tSU:STA) */ - pcf50606_delay, /* SCL high period (tHIGH) */ -}; + pcf50606_i2c_start(); + pcf50606_i2c_outb(address & 0xfe); + if (pcf50606_i2c_getack()) + { + for (i=0; i= 0) + { + pcf50606_i2c_start(); + pcf50606_i2c_outb(0x11); + if (pcf50606_i2c_getack()) + { + for(i = 0;i < count-1;i++) + buf[i] = pcf50606_i2c_inb(true); + + buf[i] = pcf50606_i2c_inb(false); + } + else + { + ret = -1; + } + } + + pcf50606_i2c_stop(); + + return ret; } int pcf50606_read(int address) @@ -130,7 +493,32 @@ int pcf50606_read(int address) int pcf50606_write_multiple(int address, const unsigned char* buf, int count) { - return i2c_write_data(0x10, address, buf, count); + unsigned char obuf[1]; + int i; + int ret = 0; + + obuf[0] = address; + + /* send write command */ + if (pcf50606_i2c_write(PCF50606_ADDR, obuf, 1) >= 0) + { + for (i=0; i