Subject: [PATCH] OMAP2/3: I2C: Add support for second and third bus From: Dirk Behme Add support to use second and third I2C bus, too. Bus 0 is still the default, but by calling i2c_set_bus_num(1/2) before doing I2C accesses, code can switch to bus 1 and 2, too. Don't forget to switch back afterwards, then. Signed-off-by: Dirk Behme --- Based on Hugo Vincent's patch http://lists.denx.de/pipermail/u-boot/2009-June/055029.html (this patch only contains the multibus support) drivers/i2c/omap24xx_i2c.c | 166 +++++++++++++++++++++--------------- include/asm-arm/arch-omap24xx/i2c.h | 55 ++++++++--- include/asm-arm/arch-omap3/i2c.h | 50 +++++++--- 3 files changed, 172 insertions(+), 99 deletions(-) Index: u-boot-main/drivers/i2c/omap24xx_i2c.c =================================================================== --- u-boot-main.orig/drivers/i2c/omap24xx_i2c.c +++ u-boot-main/drivers/i2c/omap24xx_i2c.c @@ -29,6 +29,11 @@ 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[3] = {0, 0, 0}; +static unsigned int current_bus = 0; + void i2c_init (int speed, int slaveadd) { int psc, fsscll, fssclh; @@ -95,30 +100,32 @@ void i2c_init (int speed, int slaveadd) sclh = (unsigned int)fssclh; } - writew(0x2, I2C_SYSC); /* for ES2 after soft reset */ + writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */ udelay(1000); - writew(0x0, I2C_SYSC); /* will probably self clear but */ + writew(0x0, &i2c_base->sysc); /* will probably self clear but */ - if (readw (I2C_CON) & I2C_CON_EN) { - writew (0, I2C_CON); + if (readw (&i2c_base->con) & I2C_CON_EN) { + writew (0, &i2c_base->con); udelay (50000); } - writew(psc, I2C_PSC); - writew(scll, I2C_SCLL); - writew(sclh, I2C_SCLH); + writew(psc, &i2c_base->psc); + writew(scll, &i2c_base->scll); + writew(sclh, &i2c_base->sclh); /* own address */ - writew (slaveadd, I2C_OA); - writew (I2C_CON_EN, I2C_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 | - I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE); + I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); udelay (1000); flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c_base->stat); + writew (0, &i2c_base->cnt); + + bus_initialized[current_bus] = 1; } static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) @@ -130,19 +137,19 @@ static int i2c_read_byte (u8 devaddr, u8 wait_for_bb (); /* one byte only */ - writew (1, I2C_CNT); + writew (1, &i2c_base->cnt); /* set slave address */ - writew (devaddr, I2C_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_CON); + writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, &i2c_base->con); status = wait_for_pin (); if (status & I2C_STAT_XRDY) { /* Important: have to use byte access */ - writeb (regoffset, I2C_DATA); + writeb (regoffset, &i2c_base->data); udelay (20000); - if (readw (I2C_STAT) & I2C_STAT_NACK) { + if (readw (&i2c_base->stat) & I2C_STAT_NACK) { i2c_error = 1; } } else { @@ -151,28 +158,28 @@ static int i2c_read_byte (u8 devaddr, u8 if (!i2c_error) { /* free bus, otherwise we can't use a combined transction */ - writew (0, I2C_CON); - while (readw (I2C_STAT) || (readw (I2C_CON) & I2C_CON_MST)) { + writew (0, &i2c_base->con); + while (readw (&i2c_base->stat) || (readw (&i2c_base->con) & I2C_CON_MST)) { udelay (10000); /* Have to clear pending interrupt to clear I2C_STAT */ - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c_base->stat); } wait_for_bb (); /* set slave address */ - writew (devaddr, I2C_SA); + writew (devaddr, &i2c_base->sa); /* read one byte from slave */ - writew (1, I2C_CNT); + writew (1, &i2c_base->cnt); /* need stop bit here */ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, - I2C_CON); + &i2c_base->con); status = wait_for_pin (); if (status & I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) - *value = readb (I2C_DATA); + *value = readb (&i2c_base->data); #else - *value = readw (I2C_DATA); + *value = readw (&i2c_base->data); #endif udelay (20000); } else { @@ -180,17 +187,17 @@ static int i2c_read_byte (u8 devaddr, u8 } if (!i2c_error) { - writew (I2C_CON_EN, I2C_CON); - while (readw (I2C_STAT) - || (readw (I2C_CON) & I2C_CON_MST)) { + writew (I2C_CON_EN, &i2c_base->con); + while (readw (&i2c_base->stat) + || (readw (&i2c_base->con) & I2C_CON_MST)) { udelay (10000); - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c_base->stat); } } } flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c_base->stat); + writew (0, &i2c_base->cnt); return i2c_error; } @@ -203,12 +210,12 @@ static int i2c_write_byte (u8 devaddr, u wait_for_bb (); /* two bytes */ - writew (2, I2C_CNT); + writew (2, &i2c_base->cnt); /* set slave address */ - writew (devaddr, I2C_SA); + 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_CON); + I2C_CON_STP, &i2c_base->con); /* wait until state change */ status = wait_for_pin (); @@ -216,24 +223,24 @@ static int i2c_write_byte (u8 devaddr, u if (status & I2C_STAT_XRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) /* send out 1 byte */ - writeb (regoffset, I2C_DATA); - writew (I2C_STAT_XRDY, I2C_STAT); + writeb (regoffset, &i2c_base->data); + writew (I2C_STAT_XRDY, &i2c_base->stat); status = wait_for_pin (); if ((status & I2C_STAT_XRDY)) { /* send out next 1 byte */ - writeb (value, I2C_DATA); - writew (I2C_STAT_XRDY, I2C_STAT); + writeb (value, &i2c_base->data); + writew (I2C_STAT_XRDY, &i2c_base->stat); } else { i2c_error = 1; } #else /* send out two bytes */ - writew ((value << 8) + regoffset, I2C_DATA); + writew ((value << 8) + regoffset, &i2c_base->data); #endif /* must have enough delay to allow BB bit to go low */ udelay (50000); - if (readw (I2C_STAT) & I2C_STAT_NACK) { + if (readw (&i2c_base->stat) & I2C_STAT_NACK) { i2c_error = 1; } } else { @@ -243,18 +250,18 @@ static int i2c_write_byte (u8 devaddr, u if (!i2c_error) { int eout = 200; - writew (I2C_CON_EN, I2C_CON); - while ((stat = readw (I2C_STAT)) || (readw (I2C_CON) & I2C_CON_MST)) { + writew (I2C_CON_EN, &i2c_base->con); + while ((stat = readw (&i2c_base->stat)) || (readw (&i2c_base->con) & I2C_CON_MST)) { udelay (1000); /* have to read to clear intrrupt */ - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c_base->stat); if(--eout == 0) /* better leave with error than hang */ break; } } flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c_base->stat); + writew (0, &i2c_base->cnt); return i2c_error; } @@ -265,14 +272,14 @@ static void flush_fifo(void) * you get a bus error */ while(1){ - stat = readw(I2C_STAT); + stat = readw(&i2c_base->stat); if(stat == I2C_STAT_RRDY){ #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) - readb(I2C_DATA); + readb(&i2c_base->data); #else - readw(I2C_DATA); + readw(&i2c_base->data); #endif - writew(I2C_STAT_RRDY,I2C_STAT); + writew(I2C_STAT_RRDY,&i2c_base->stat); udelay(1000); }else break; @@ -283,7 +290,7 @@ int i2c_probe (uchar chip) { int res = 1; /* default = fail */ - if (chip == readw (I2C_OA)) { + if (chip == readw (&i2c_base->oa)) { return res; } @@ -291,27 +298,27 @@ int i2c_probe (uchar chip) wait_for_bb (); /* try to read one byte */ - writew (1, I2C_CNT); + writew (1, &i2c_base->cnt); /* set slave address */ - writew (chip, I2C_SA); + writew (chip, &i2c_base->sa); /* stop bit needed here */ - writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON); + writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con); /* enough delay for the NACK bit set */ udelay (50000); - if (!(readw (I2C_STAT) & I2C_STAT_NACK)) { + if (!(readw (&i2c_base->stat) & I2C_STAT_NACK)) { res = 0; /* success case */ flush_fifo(); - writew(0xFFFF, I2C_STAT); + writew(0xFFFF, &i2c_base->stat); } else { - writew(0xFFFF, I2C_STAT); /* failue, clear sources*/ - writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */ + writew(0xFFFF, &i2c_base->stat); /* failue, clear sources*/ + writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); /* finish up xfer */ udelay(20000); wait_for_bb (); } flush_fifo(); - writew (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/ - writew(0xFFFF, I2C_STAT); + writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/ + writew(0xFFFF, &i2c_base->stat); return res; } @@ -370,17 +377,17 @@ static void wait_for_bb (void) int timeout = 10; u16 stat; - writew(0xFFFF, I2C_STAT); /* clear current interruts...*/ - while ((stat = readw (I2C_STAT) & I2C_STAT_BB) && timeout--) { - writew (stat, I2C_STAT); + writew(0xFFFF, &i2c_base->stat); /* clear current interruts...*/ + while ((stat = readw (&i2c_base->stat) & I2C_STAT_BB) && timeout--) { + writew (stat, &i2c_base->stat); udelay (50000); } if (timeout <= 0) { printf ("timed out in wait_for_bb: I2C_STAT=%x\n", - readw (I2C_STAT)); + readw (&i2c_base->stat)); } - writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/ + writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ } static u16 wait_for_pin (void) @@ -390,7 +397,7 @@ static u16 wait_for_pin (void) do { udelay (1000); - status = readw (I2C_STAT); + 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 | @@ -398,8 +405,33 @@ static u16 wait_for_pin (void) if (timeout <= 0) { printf ("timed out in wait_for_pin: I2C_STAT=%x\n", - readw (I2C_STAT)); - writew(0xFFFF, I2C_STAT); + readw (&i2c_base->stat)); + writew(0xFFFF, &i2c_base->stat); } return status; } + +int i2c_set_bus_num(unsigned int bus) +{ + if ((bus < 0) || (bus >= I2C_BUS_MAX)) { + printf("Bad bus: %d\n", bus); + return -1; + } + +#ifdef CONFIG_OMAP34XX + if (bus == 2) + i2c_base = (struct i2c *)I2C_BASE3; + else +#endif + if (bus == 1) + i2c_base = (struct i2c *)I2C_BASE2; + else + i2c_base = (struct i2c *)I2C_BASE1; + + current_bus = bus; + + if(!bus_initialized[current_bus]) + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + return 0; +} Index: u-boot-main/include/asm-arm/arch-omap3/i2c.h =================================================================== --- u-boot-main.orig/include/asm-arm/arch-omap3/i2c.h +++ u-boot-main/include/asm-arm/arch-omap3/i2c.h @@ -25,21 +25,39 @@ #define I2C_DEFAULT_BASE I2C_BASE1 -#define I2C_REV (I2C_DEFAULT_BASE + 0x00) -#define I2C_IE (I2C_DEFAULT_BASE + 0x04) -#define I2C_STAT (I2C_DEFAULT_BASE + 0x08) -#define I2C_IV (I2C_DEFAULT_BASE + 0x0c) -#define I2C_BUF (I2C_DEFAULT_BASE + 0x14) -#define I2C_CNT (I2C_DEFAULT_BASE + 0x18) -#define I2C_DATA (I2C_DEFAULT_BASE + 0x1c) -#define I2C_SYSC (I2C_DEFAULT_BASE + 0x20) -#define I2C_CON (I2C_DEFAULT_BASE + 0x24) -#define I2C_OA (I2C_DEFAULT_BASE + 0x28) -#define I2C_SA (I2C_DEFAULT_BASE + 0x2c) -#define I2C_PSC (I2C_DEFAULT_BASE + 0x30) -#define I2C_SCLL (I2C_DEFAULT_BASE + 0x34) -#define I2C_SCLH (I2C_DEFAULT_BASE + 0x38) -#define I2C_SYSTEST (I2C_DEFAULT_BASE + 0x3c) +struct i2c { + unsigned short rev; /* 0x00 */ + unsigned short res1; + unsigned short ie; /* 0x04 */ + unsigned short res2; + unsigned short stat; /* 0x08 */ + unsigned short res3; + unsigned short iv; /* 0x0C */ + unsigned short res4[3]; + unsigned short buf; /* 0x14 */ + unsigned short res5; + unsigned short cnt; /* 0x18 */ + unsigned short res6; + unsigned short data; /* 0x1C */ + unsigned short res7; + unsigned short sysc; /* 0x20 */ + unsigned short res8; + unsigned short con; /* 0x24 */ + unsigned short res9; + unsigned short oa; /* 0x28 */ + unsigned short res10; + unsigned short sa; /* 0x2C */ + unsigned short res11; + unsigned short psc; /* 0x30 */ + unsigned short res12; + unsigned short scll; /* 0x34 */ + unsigned short res13; + unsigned short sclh; /* 0x38 */ + unsigned short res14; + unsigned short systest; /* 0x3c */ +}; + +#define I2C_BUS_MAX 3 /* I2C masks */ @@ -181,4 +199,6 @@ #define I2C_PSC_MAX 0x0f #define I2C_PSC_MIN 0x00 +extern int i2c_set_bus_num(unsigned int); + #endif /* _I2C_H_ */ Index: u-boot-main/include/asm-arm/arch-omap24xx/i2c.h =================================================================== --- u-boot-main.orig/include/asm-arm/arch-omap24xx/i2c.h +++ u-boot-main/include/asm-arm/arch-omap24xx/i2c.h @@ -6,7 +6,7 @@ * project. * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as + * moify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * @@ -23,24 +23,44 @@ #ifndef _OMAP24XX_I2C_H_ #define _OMAP24XX_I2C_H_ -#define I2C_BASE 0x48070000 +#define I2C_BASE1 0x48070000 #define I2C_BASE2 0x48072000 /* nothing hooked up on h4 */ -#define I2C_REV (I2C_BASE + 0x00) -#define I2C_IE (I2C_BASE + 0x04) -#define I2C_STAT (I2C_BASE + 0x08) -#define I2C_IV (I2C_BASE + 0x0c) -#define I2C_BUF (I2C_BASE + 0x14) -#define I2C_CNT (I2C_BASE + 0x18) -#define I2C_DATA (I2C_BASE + 0x1c) -#define I2C_SYSC (I2C_BASE + 0x20) -#define I2C_CON (I2C_BASE + 0x24) -#define I2C_OA (I2C_BASE + 0x28) -#define I2C_SA (I2C_BASE + 0x2c) -#define I2C_PSC (I2C_BASE + 0x30) -#define I2C_SCLL (I2C_BASE + 0x34) -#define I2C_SCLH (I2C_BASE + 0x38) -#define I2C_SYSTEST (I2C_BASE + 0x3c) +#define I2C_DEFAULT_BASE I2C_BASE1 + +struct i2c { + unsigned short rev; /* 0x00 */ + unsigned short res1; + unsigned short ie; /* 0x04 */ + unsigned short res2; + unsigned short stat; /* 0x08 */ + unsigned short res3; + unsigned short iv; /* 0x0C */ + unsigned short res4[3]; + unsigned short buf; /* 0x14 */ + unsigned short res5; + unsigned short cnt; /* 0x18 */ + unsigned short res6; + unsigned short data; /* 0x1C */ + unsigned short res7; + unsigned short sysc; /* 0x20 */ + unsigned short res8; + unsigned short con; /* 0x24 */ + unsigned short res9; + unsigned short oa; /* 0x28 */ + unsigned short res10; + unsigned short sa; /* 0x2C */ + unsigned short res11; + unsigned short psc; /* 0x30 */ + unsigned short res12; + unsigned short scll; /* 0x34 */ + unsigned short res13; + unsigned short sclh; /* 0x38 */ + unsigned short res14; + unsigned short systest; /* 0x3c */ +}; + +#define I2C_BUS_MAX 2 /* I2C masks */ @@ -147,5 +167,6 @@ #define I2C_PSC_MAX 0x0f #define I2C_PSC_MIN 0x00 +extern int i2c_set_bus_num(unsigned int); #endif