1
0
Fork 0
forked from len0rd/rockbox

iPod Classic: i2c updates

Change-Id: Ib516f3f52cf619fb44dc1bb6982b635c49f53a8f
This commit is contained in:
Cástor Muñoz 2016-05-25 23:54:24 +02:00
parent 2d850b7c66
commit 9e284c11b1
3 changed files with 49 additions and 20 deletions

View file

@ -750,18 +750,20 @@
/////INTERRUPTS///// /////INTERRUPTS/////
#define IRQ_TIMER32 7 #define IRQ_TIMER32 7
#define IRQ_TIMER 8 #define IRQ_TIMER 8
#define IRQ_SPI(i) (9+i) /* TBC */ #define IRQ_SPI(i) (9+(i)) /* TBC */
#define IRQ_SPI0 9 #define IRQ_SPI0 9
#define IRQ_SPI1 10 #define IRQ_SPI1 10
#define IRQ_SPI2 11 #define IRQ_SPI2 11
#define IRQ_LCD 14 #define IRQ_LCD 14
#define IRQ_DMAC(d) (16+d) #define IRQ_DMAC(d) (16+(d))
#define IRQ_DMAC0 16 #define IRQ_DMAC0 16
#define IRQ_DMAC1 17 #define IRQ_DMAC1 17
#define IRQ_USB_FUNC 19 #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_WHEEL 23
#define IRQ_UART(i) (24+i) #define IRQ_UART(i) (24+(i))
#define IRQ_UART0 24 #define IRQ_UART0 24
#define IRQ_UART1 25 #define IRQ_UART1 25
#define IRQ_UART2 26 #define IRQ_UART2 26

View file

@ -133,6 +133,9 @@ bool dbg_hw_info(void)
_DEBUG_PRINTF("accessory present: %s", _DEBUG_PRINTF("accessory present: %s",
pmu_accessory_present() ? "true" : "false"); pmu_accessory_present() ? "true" : "false");
#endif #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 #ifdef UC870X_DEBUG
else if(state==2) else if(state==2)

View file

@ -38,6 +38,29 @@
* blocks the calling thread for the entire duraton of the i2c transfer but * blocks the calling thread for the entire duraton of the i2c transfer but
uses wakeup_wait/wakeup_signal to allow other threads to run. uses wakeup_wait/wakeup_signal to allow other threads to run.
* ACK from slave is not checked, so functions never return an error * 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]; static struct mutex i2c_mtx[2];
@ -45,12 +68,11 @@ static struct mutex i2c_mtx[2];
static void i2c_on(int bus) static void i2c_on(int bus)
{ {
/* enable I2C clock */ /* 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 */ (0 << 6) | /* CLKSEL = PCLK/16 */
(1 << 5) | /* INT_EN */
(1 << 4) | /* IRQ clear */
(7 << 0); /* CK_REG */ (7 << 0); /* CK_REG */
/* serial output on */ /* serial output on */
@ -63,7 +85,7 @@ static void i2c_off(int bus)
IICSTAT(bus) = 0; IICSTAT(bus) = 0;
/* disable I2C clock */ /* disable I2C clock */
PWRCON(1) |= (1 << 4); clockgate_enable(I2CCLKGATE(bus), false);
} }
void i2c_init() void i2c_init()
@ -80,7 +102,6 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch
/* START */ /* START */
IICDS(bus) = slave & ~1; IICDS(bus) = slave & ~1;
IICSTAT(bus) = 0xF0; IICSTAT(bus) = 0xF0;
IICCON(bus) = 0xB3;
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 1; return 1;
@ -88,7 +109,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch
if (address >= 0) { if (address >= 0) {
/* write address */ /* write address */
IICDS(bus) = address; IICDS(bus) = address;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 2; return 2;
@ -97,7 +118,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch
/* write data */ /* write data */
while (len--) { while (len--) {
IICDS(bus) = *data++; IICDS(bus) = *data++;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 4; return 4;
@ -105,7 +126,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch
/* STOP */ /* STOP */
IICSTAT(bus) = 0xD0; IICSTAT(bus) = 0xD0;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICSTAT(bus) & (1 << 5)) != 0) while ((IICSTAT(bus) & (1 << 5)) != 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 5; return 5;
@ -123,14 +144,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da
/* START */ /* START */
IICDS(bus) = slave & ~1; IICDS(bus) = slave & ~1;
IICSTAT(bus) = 0xF0; IICSTAT(bus) = 0xF0;
IICCON(bus) = 0xB3;
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 1; return 1;
/* write address */ /* write address */
IICDS(bus) = address; IICDS(bus) = address;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 2; return 2;
@ -139,13 +159,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da
/* (repeated) START */ /* (repeated) START */
IICDS(bus) = slave | 1; IICDS(bus) = slave | 1;
IICSTAT(bus) = 0xB0; IICSTAT(bus) = 0xB0;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 3; return 3;
while (len--) { while (len--) {
IICCON(bus) = (len == 0) ? 0x33 : 0xB3; /* NAK or ACK */ IICCON(bus) &= ~(len ? 0 : 0x80); /* ACK or NAK */
while ((IICCON(bus) & 0x10) == 0) while ((IICCON(bus) & 0x10) == 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 4; return 4;
@ -154,7 +174,7 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da
/* STOP */ /* STOP */
IICSTAT(bus) = 0x90; IICSTAT(bus) = 0x90;
IICCON(bus) = 0xB3; IICCON(bus) = IICCON(bus);
while ((IICSTAT(bus) & (1 << 5)) != 0) while ((IICSTAT(bus) & (1 << 5)) != 0)
if (TIME_AFTER(USEC_TIMER, timeout)) if (TIME_AFTER(USEC_TIMER, timeout))
return 5; return 5;
@ -163,12 +183,15 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da
return 0; 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 i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data)
{ {
int ret; int ret;
mutex_lock(&i2c_mtx[bus]); mutex_lock(&i2c_mtx[bus]);
ret = i2c_wr(bus, slave, address, len, data); ret = i2c_wr(bus, slave, address, len, data);
mutex_unlock(&i2c_mtx[bus]); mutex_unlock(&i2c_mtx[bus]);
if (ret) i2c_wr_err++;
return ret; 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]); mutex_lock(&i2c_mtx[bus]);
ret = i2c_rd(bus, slave, address, len, data); ret = i2c_rd(bus, slave, address, len, data);
mutex_unlock(&i2c_mtx[bus]); mutex_unlock(&i2c_mtx[bus]);
if (ret) i2c_rd_err++;
return ret; return ret;
} }