X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fi2c%2Fomap24xx_i2c.c;h=81193b0e6eb7b69de254c7187d00aedc6e623fdf;hb=402d17fc4c406fe49a7b2d94aee640f389a68738;hp=a72d1a125702dd7f3f55ec2476a80b91ad6d7fea;hpb=37a3bda0c9c8a2ffbf7e2a9e121177a3385a0626;p=karo-tx-uboot.git diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index a72d1a1257..81193b0e6e 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -27,20 +27,26 @@ #include "omap24xx_i2c.h" +DECLARE_GLOBAL_DATA_PTR; + #define I2C_TIMEOUT 1000 -static void wait_for_bb (void); -static u16 wait_for_pin (void); +static void wait_for_bb(void); +static u16 wait_for_pin(void); static void flush_fifo(void); -static struct i2c *i2c_base = (struct i2c *)I2C_DEFAULT_BASE; - -static unsigned int bus_initialized[I2C_BUS_MAX]; -static unsigned int current_bus; +/* + * For SPL boot some boards need i2c before SDRAM is initialised so force + * variables to live in SRAM + */ +static struct i2c __attribute__((section (".data"))) *i2c_base = + (struct i2c *)I2C_DEFAULT_BASE; +static unsigned int __attribute__((section (".data"))) bus_initialized[I2C_BUS_MAX] = + { [0 ... (I2C_BUS_MAX-1)] = 0 }; +static unsigned int __attribute__((section (".data"))) current_bus = 0; -void i2c_init (int speed, int slaveadd) +void i2c_init(int speed, int slaveadd) { - DECLARE_GLOBAL_DATA_PTR; int psc, fsscll, fssclh; int hsscll = 0, hssclh = 0; u32 scll, sclh; @@ -72,7 +78,7 @@ void i2c_init (int speed, int slaveadd) fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM; if (((fsscll < 0) || (fssclh < 0)) || ((fsscll > 255) || (fssclh > 255))) { - printf("Error : I2C initializing first phase clock\n"); + puts("Error : I2C initializing first phase clock\n"); return; } @@ -83,7 +89,7 @@ void i2c_init (int speed, int slaveadd) hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM; if (((fsscll < 0) || (fssclh < 0)) || ((fsscll > 255) || (fssclh > 255))) { - printf("Error : I2C initializing second phase clock\n"); + puts("Error : I2C initializing second phase clock\n"); return; } @@ -98,7 +104,7 @@ void i2c_init (int speed, int slaveadd) fssclh -= I2C_FASTSPEED_SCLH_TRIM; if (((fsscll < 0) || (fssclh < 0)) || ((fsscll > 255) || (fssclh > 255))) { - printf("Error : I2C initializing clock\n"); + puts("Error : I2C initializing clock\n"); return; } @@ -106,9 +112,9 @@ void i2c_init (int speed, int slaveadd) sclh = (unsigned int)fssclh; } - if (readw (&i2c_base->con) & I2C_CON_EN) { - writew (0, &i2c_base->con); - udelay (50000); + if (readw(&i2c_base->con) & I2C_CON_EN) { + writew(0, &i2c_base->con); + udelay(50000); } writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */ @@ -117,7 +123,7 @@ void i2c_init (int speed, int slaveadd) writew(I2C_CON_EN, &i2c_base->con); while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) { if (timeout <= 0) { - printf("ERROR: Timeout in soft-reset\n"); + puts("ERROR: Timeout in soft-reset\n"); return; } udelay(1000); @@ -129,35 +135,36 @@ void i2c_init (int speed, int slaveadd) writew(sclh, &i2c_base->sclh); /* own address */ - writew (slaveadd, &i2c_base->oa); - writew (I2C_CON_EN, &i2c_base->con); + writew(slaveadd, &i2c_base->oa); + writew(I2C_CON_EN, &i2c_base->con); /* have to enable intrrupts or OMAP i2c module doesn't work */ - writew (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | + writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); - udelay (1000); + udelay(1000); flush_fifo(); - writew (0xFFFF, &i2c_base->stat); - writew (0, &i2c_base->cnt); + writew(0xFFFF, &i2c_base->stat); + writew(0, &i2c_base->cnt); if (gd->flags & GD_FLG_RELOC) bus_initialized[current_bus] = 1; } -static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) +static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value) { int i2c_error = 0; u16 status; /* wait until bus not busy */ - wait_for_bb (); + wait_for_bb(); /* one byte only */ - writew (1, &i2c_base->cnt); + writew(1, &i2c_base->cnt); /* set slave address */ - writew (devaddr, &i2c_base->sa); + writew(devaddr, &i2c_base->sa); /* no stop bit needed here */ - writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, &i2c_base->con); + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | + I2C_CON_TRX, &i2c_base->con); /* send register offset */ while (1) { @@ -195,7 +202,7 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) } if (status & I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) *value = readb(&i2c_base->data); #else *value = readw(&i2c_base->data); @@ -210,79 +217,8 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) read_exit: flush_fifo(); - writew (0xFFFF, &i2c_base->stat); - writew (0, &i2c_base->cnt); - return i2c_error; -} - -static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) -{ - int i2c_error = 0; - u16 status; - - /* wait until bus not busy */ - wait_for_bb (); - - /* two bytes */ - writew (2, &i2c_base->cnt); - /* set slave address */ - writew (devaddr, &i2c_base->sa); - /* stop bit needed here */ - writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); - - while (1) { - status = wait_for_pin(); - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - goto write_exit; - } - if (status & I2C_STAT_XRDY) { -#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) - /* send register offset */ - writeb(regoffset, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); - - while (1) { - status = wait_for_pin(); - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - goto write_exit; - } - if (status & I2C_STAT_XRDY) { - /* send data */ - writeb(value, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; - } - } - break; -#else - /* send out two bytes */ - writew((value << 8) + regoffset, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); -#endif - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; - } - } - - wait_for_bb(); - - status = readw(&i2c_base->stat); - if (status & I2C_STAT_NACK) - i2c_error = 1; - -write_exit: - flush_fifo(); - writew (0xFFFF, &i2c_base->stat); - writew (0, &i2c_base->cnt); + writew(0xFFFF, &i2c_base->stat); + writew(0, &i2c_base->cnt); return i2c_error; } @@ -292,44 +228,43 @@ static void flush_fifo(void) /* note: if you try and read data when its not there or ready * you get a bus error */ - while(1){ + while (1) { stat = readw(&i2c_base->stat); - if(stat == I2C_STAT_RRDY){ + if (stat == I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) readb(&i2c_base->data); #else readw(&i2c_base->data); #endif - writew(I2C_STAT_RRDY,&i2c_base->stat); + writew(I2C_STAT_RRDY, &i2c_base->stat); udelay(1000); - }else + } else break; } } -int i2c_probe (uchar chip) +int i2c_probe(uchar chip) { u16 status; int res = 1; /* default = fail */ - if (chip == readw (&i2c_base->oa)) { + if (chip == readw(&i2c_base->oa)) return res; - } /* wait until bus not busy */ - wait_for_bb (); + wait_for_bb(); /* try to read one byte */ - writew (1, &i2c_base->cnt); + writew(1, &i2c_base->cnt); /* set slave address */ - writew (chip, &i2c_base->sa); + writew(chip, &i2c_base->sa); /* stop bit needed here */ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con); while (1) { status = wait_for_pin(); - if (status == 0) { + if (status == 0 || status & I2C_STAT_AL) { res = 1; goto probe_exit; } @@ -347,7 +282,7 @@ int i2c_probe (uchar chip) if (status & I2C_STAT_RRDY) { res = 0; #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) readb(&i2c_base->data); #else readw(&i2c_base->data); @@ -358,29 +293,30 @@ int i2c_probe (uchar chip) probe_exit: flush_fifo(); - writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/ + /* don't allow any more data in... we don't want it. */ + writew(0, &i2c_base->cnt); writew(0xFFFF, &i2c_base->stat); return res; } -int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { int i; if (alen > 1) { - printf ("I2C read: addr len %d not supported\n", alen); + printf("I2C read: addr len %d not supported\n", alen); return 1; } if (addr + len > 256) { - printf ("I2C read: address out of range\n"); + puts("I2C read: address out of range\n"); return 1; } for (i = 0; i < len; i++) { - if (i2c_read_byte (chip, addr + i, &buffer[i])) { - printf ("I2C read: I/O error\n"); - i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + if (i2c_read_byte(chip, addr + i, &buffer[i])) { + puts("I2C read: I/O error\n"); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); return 1; } } @@ -388,65 +324,116 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) return 0; } -int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { int i; + u16 status; + int i2c_error = 0; if (alen > 1) { - printf ("I2C read: addr len %d not supported\n", alen); + printf("I2C write: addr len %d not supported\n", alen); return 1; } if (addr + len > 256) { - printf ("I2C read: address out of range\n"); + printf("I2C write: address 0x%x + 0x%x out of range\n", + addr, len); return 1; } + /* wait until bus not busy */ + wait_for_bb(); + + /* start address phase - will write regoffset + len bytes data */ + /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */ + writew(alen + len, &i2c_base->cnt); + /* set slave address */ + writew(chip, &i2c_base->sa); + /* stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_STP, &i2c_base->con); + + /* Send address byte */ + status = wait_for_pin(); + + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + printf("error waiting for i2c address ACK (status=0x%x)\n", + status); + goto write_exit; + } + + if (status & I2C_STAT_XRDY) { + writeb(addr & 0xFF, &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } else { + i2c_error = 1; + printf("i2c bus not ready for transmit (status=0x%x)\n", + status); + goto write_exit; + } + + /* address phase is over, now write data */ for (i = 0; i < len; i++) { - if (i2c_write_byte (chip, addr + i, buffer[i])) { - printf ("I2C read: I/O error\n"); - i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); - return 1; + status = wait_for_pin(); + + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + printf("i2c error waiting for data ACK (status=0x%x)\n", + status); + goto write_exit; + } + + if (status & I2C_STAT_XRDY) { + writeb(buffer[i], &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } else { + i2c_error = 1; + printf("i2c bus not ready for Tx (i=%d)\n", i); + goto write_exit; } } - return 0; +write_exit: + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + return i2c_error; } -static void wait_for_bb (void) +static void wait_for_bb(void) { int timeout = I2C_TIMEOUT; u16 stat; - writew(0xFFFF, &i2c_base->stat); /* clear current interruts...*/ - while ((stat = readw (&i2c_base->stat) & I2C_STAT_BB) && timeout--) { - writew (stat, &i2c_base->stat); + writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/ + while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) { + writew(stat, &i2c_base->stat); udelay(1000); } if (timeout <= 0) { - printf ("timed out in wait_for_bb: I2C_STAT=%x\n", - readw (&i2c_base->stat)); + printf("timed out in wait_for_bb: I2C_STAT=%x\n", + readw(&i2c_base->stat)); } writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ } -static u16 wait_for_pin (void) +static u16 wait_for_pin(void) { u16 status; int timeout = I2C_TIMEOUT; do { - udelay (1000); - status = readw (&i2c_base->stat); - } while ( !(status & + udelay(1000); + status = readw(&i2c_base->stat); + } while (!(status & (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | I2C_STAT_AL)) && timeout--); if (timeout <= 0) { - printf ("timed out in wait_for_pin: I2C_STAT=%x\n", - readw (&i2c_base->stat)); + printf("timed out in wait_for_pin: I2C_STAT=%x\n", + readw(&i2c_base->stat)); writew(0xFFFF, &i2c_base->stat); status = 0; } @@ -461,7 +448,7 @@ int i2c_set_bus_num(unsigned int bus) return -1; } -#if I2C_BUS_MAX==3 +#if I2C_BUS_MAX == 3 if (bus == 2) i2c_base = (struct i2c *)I2C_BASE3; else @@ -473,7 +460,7 @@ int i2c_set_bus_num(unsigned int bus) current_bus = bus; - if(!bus_initialized[current_bus]) + if (!bus_initialized[current_bus]) i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); return 0;