diff options
author | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-25 23:54:24 +0200 |
---|---|---|
committer | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-26 09:06:30 +0200 |
commit | 9e284c11b11a09adae8073a3347480c1d580e0cc (patch) | |
tree | fa428a9a4de8be0042678d869bbd1e5cf18f1ef6 | |
parent | 2d850b7c660aa05433620083660c3b1f5f0b2592 (diff) |
iPod Classic: i2c updates
Change-Id: Ib516f3f52cf619fb44dc1bb6982b635c49f53a8f
-rw-r--r-- | firmware/export/s5l8702.h | 10 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/debug-s5l8702.c | 3 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/i2c-s5l8702.c | 56 |
3 files changed, 49 insertions, 20 deletions
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h index 59170b04ea..6500f69d37 100644 --- a/firmware/export/s5l8702.h +++ b/firmware/export/s5l8702.h @@ -750,18 +750,20 @@ /////INTERRUPTS///// #define IRQ_TIMER32 7 #define IRQ_TIMER 8 -#define IRQ_SPI(i) (9+i) /* TBC */ +#define IRQ_SPI(i) (9+(i)) /* TBC */ #define IRQ_SPI0 9 #define IRQ_SPI1 10 #define IRQ_SPI2 11 #define IRQ_LCD 14 -#define IRQ_DMAC(d) (16+d) +#define IRQ_DMAC(d) (16+(d)) #define IRQ_DMAC0 16 #define IRQ_DMAC1 17 #define IRQ_USB_FUNC 19 -#define IRQ_I2C 21 /* TBC */ +#define IRQ_I2C(i) (21+(i)) +#define IRQ_I2C0 21 +#define IRQ_I2C1 22 #define IRQ_WHEEL 23 -#define IRQ_UART(i) (24+i) +#define IRQ_UART(i) (24+(i)) #define IRQ_UART0 24 #define IRQ_UART1 25 #define IRQ_UART2 26 diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index cead1b7219..3faf9dfc99 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c @@ -133,6 +133,9 @@ bool dbg_hw_info(void) _DEBUG_PRINTF("accessory present: %s", pmu_accessory_present() ? "true" : "false"); #endif + extern unsigned long i2c_rd_err, i2c_wr_err; + line++; + _DEBUG_PRINTF("i2c rd/wr errors:: %lu/%lu", i2c_rd_err, i2c_wr_err); } #ifdef UC870X_DEBUG else if(state==2) diff --git a/firmware/target/arm/s5l8702/i2c-s5l8702.c b/firmware/target/arm/s5l8702/i2c-s5l8702.c index d76bbe6c06..a795c9f18c 100644 --- a/firmware/target/arm/s5l8702/i2c-s5l8702.c +++ b/firmware/target/arm/s5l8702/i2c-s5l8702.c @@ -26,18 +26,41 @@ #include "clocking-s5l8702.h" /* Driver for the s5l8700 built-in I2C controller in master mode - + Both the i2c_read and i2c_write function take the following arguments: * slave, the address of the i2c slave device to read from / write to * address, optional sub-address in the i2c slave (unused if -1) * len, number of bytes to be transfered * data, pointer to data to be transfered A return value < 0 indicates an error. - + Note: * blocks the calling thread for the entire duraton of the i2c transfer but uses wakeup_wait/wakeup_signal to allow other threads to run. * ACK from slave is not checked, so functions never return an error + + Fixme: + * actually there is no STOP + i2c_off() on error + * very rare random errors when reading and/or(?) writing registers on some + builds/devices, hard to trace, not a 'delay' issue, it seems related + with alignment of STRs and/or(?) LDRs, code cache lines, pipelines... + The new code tries to mix STRs and LDRs at some points but ATM it is + unknown if it might solve or mitigate the problem. Probably it could be + really fixed using wait_rdy() before accessing any register, as OF does. +*/ + +/* s5l8702 I2C controller is similar to s5l8700, known differences are: + + * IICCON[5] is not used in s5l8702. + * IICCON[13:8] are used to enable interrupts. + IICUNK20[13:8] are used to read the status and write-clear interrupts. + Known interrupts: + [13] STOP on bus (TBC) + [12] START on bus (TBC) + [8] byte transmited or received in Master mode (not tested in Slave) + * IICCON[4] does not clear interrupts, it is enabled when a byte is + transmited or received, in Master mode the tx/rx of the next byte + starts when it is written as "1". */ static struct mutex i2c_mtx[2]; @@ -45,12 +68,11 @@ static struct mutex i2c_mtx[2]; static void i2c_on(int bus) { /* enable I2C clock */ - PWRCON(1) &= ~(1 << 4); + clockgate_enable(I2CCLKGATE(bus), true); - IICCON(bus) = (1 << 7) | /* ACK_GEN */ + IICCON(bus) = (0 << 8) | /* INT_EN = disabled */ + (1 << 7) | /* ACK_GEN */ (0 << 6) | /* CLKSEL = PCLK/16 */ - (1 << 5) | /* INT_EN */ - (1 << 4) | /* IRQ clear */ (7 << 0); /* CK_REG */ /* serial output on */ @@ -63,7 +85,7 @@ static void i2c_off(int bus) IICSTAT(bus) = 0; /* disable I2C clock */ - PWRCON(1) |= (1 << 4); + clockgate_enable(I2CCLKGATE(bus), false); } void i2c_init() @@ -80,7 +102,6 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch /* START */ IICDS(bus) = slave & ~1; IICSTAT(bus) = 0xF0; - IICCON(bus) = 0xB3; while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 1; @@ -88,7 +109,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch if (address >= 0) { /* write address */ IICDS(bus) = address; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 2; @@ -97,7 +118,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch /* write data */ while (len--) { IICDS(bus) = *data++; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 4; @@ -105,7 +126,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch /* STOP */ IICSTAT(bus) = 0xD0; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICSTAT(bus) & (1 << 5)) != 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 5; @@ -123,14 +144,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da /* START */ IICDS(bus) = slave & ~1; IICSTAT(bus) = 0xF0; - IICCON(bus) = 0xB3; while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 1; /* write address */ IICDS(bus) = address; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 2; @@ -139,13 +159,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da /* (repeated) START */ IICDS(bus) = slave | 1; IICSTAT(bus) = 0xB0; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 3; while (len--) { - IICCON(bus) = (len == 0) ? 0x33 : 0xB3; /* NAK or ACK */ + IICCON(bus) &= ~(len ? 0 : 0x80); /* ACK or NAK */ while ((IICCON(bus) & 0x10) == 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 4; @@ -154,7 +174,7 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da /* STOP */ IICSTAT(bus) = 0x90; - IICCON(bus) = 0xB3; + IICCON(bus) = IICCON(bus); while ((IICSTAT(bus) & (1 << 5)) != 0) if (TIME_AFTER(USEC_TIMER, timeout)) return 5; @@ -163,12 +183,15 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da return 0; } +unsigned long i2c_rd_err, i2c_wr_err; + int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data) { int ret; mutex_lock(&i2c_mtx[bus]); ret = i2c_wr(bus, slave, address, len, data); mutex_unlock(&i2c_mtx[bus]); + if (ret) i2c_wr_err++; return ret; } @@ -178,6 +201,7 @@ int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char * mutex_lock(&i2c_mtx[bus]); ret = i2c_rd(bus, slave, address, len, data); mutex_unlock(&i2c_mtx[bus]); + if (ret) i2c_rd_err++; return ret; } |