[U-Boot] [PATCH/RFC] Better I2C support for OMAP3

Hi everyone,
This patch improves I2C support on OMAP3 platforms, including supporting the second and third I2C controllers (mainline only supports the first controller), and supporting writes where alen=0 (i.e. no register address - this was needed for some I2C devices I needed to drive from u-boot).
Tested on Gumstix Overo with several I2C devices, on I2C1 and 3.
The multi-bus support is mostly from this patch: http://www.beagleboard.org/gitweb/?p=u-boot-arm.git;a=commit;h=52eddcd07c2e7...
Best regards, Hugo Vincent
Signed-off-by: Hugo Vincent hugo.vincent@gmail.com
diff --git a/board/omap3/common/power.c b/board/omap3/common/power.c index 4908e5b..efc5dd4 100644 --- a/board/omap3/common/power.c +++ b/board/omap3/common/power.c @@ -42,6 +42,7 @@ void power_init_r(void) unsigned char byte;
#ifdef CONFIG_DRIVER_OMAP34XX_I2C + i2c_set_bus_num(0); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 16439ac..6332965 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -1324,6 +1324,7 @@ U_BOOT_CMD( #endif ); #endif /* CONFIG_I2C_CMD_TREE */ +#if !defined(CONFIG_I2C_CMD_TREE) U_BOOT_CMD( imd, 4, 1, do_i2c_md, \ "i2c memory display", \ @@ -1378,6 +1379,7 @@ U_BOOT_CMD( " (valid chip values 50..57)\n" ); #endif +#endif /* !defined(CONFIG_I2C_CMD_TREE) */
#if defined(CONFIG_I2C_MUX)
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 6784603..424f172 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -1,7 +1,7 @@ /* * Basic I2C functions * - * Copyright (c) 2004 Texas Instruments + * Copyright (c) 2004, 2009 Texas Instruments * * This package is free software; you can redistribute it and/or * modify it under the terms of the license found in the file @@ -18,6 +18,7 @@ * * Adapted for OMAP2420 I2C, r-woodruff2@ti.com * + * Some additions by Hugo Vincent hugo.vincent@gmail.com June 2009 */
#include <common.h> @@ -25,40 +24,44 @@ #include <asm/arch/i2c.h> #include <asm/io.h>
+#ifdef CONFIG_OMAP34XX +#define I2C_NUM_IF 3 +#else +#define I2C_NUM_IF 2 +#endif + static void wait_for_bb (void); static u16 wait_for_pin (void); static void flush_fifo(void);
+static i2c_t *i2c = (i2c_t *)I2C_DEFAULT_BASE; + void i2c_init (int speed, int slaveadd) { - u16 scl; - - writew(0x2, I2C_SYSC); /* for ES2 after soft reset */ + writew(0x2, &i2c->sysc); /* for ES2 after soft reset */ udelay(1000); - writew(0x0, I2C_SYSC); /* will probably self clear but */ + writew(0x0, &i2c->sysc); /* will probably self clear but */
- if (readw (I2C_CON) & I2C_CON_EN) { - writew (0, I2C_CON); - udelay (50000); + if (readw (&i2c->con) & I2C_CON_EN) { + writew (0, &i2c->con); + udelay (10000); }
- /* 12MHz I2C module clock */ - writew (0, I2C_PSC); - speed = speed/1000; /* 100 or 400 */ - scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */ - writew (scl, I2C_SCLL); - writew (scl, I2C_SCLH); + /* Timings from TRM, tested with scope - 100 kHz standard speed */ + writew (23, &i2c->psc); + writew (13, &i2c->scll); + writew (15, &i2c->sclh); /* own address */ - writew (slaveadd, I2C_OA); - writew (I2C_CON_EN, I2C_CON); + writew (slaveadd, &i2c->oa); + writew (I2C_CON_EN, &i2c->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->ie); udelay (1000); flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c->stat); + writew (0, &i2c->cnt); }
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) @@ -70,19 +77,19 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) wait_for_bb ();
/* one byte only */ - writew (1, I2C_CNT); + writew (1, &i2c->cnt); /* set slave address */ - writew (devaddr, I2C_SA); + writew (devaddr, &i2c->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-
con);
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) { /* Important: have to use byte access */ - writeb (regoffset, I2C_DATA); + writeb (regoffset, &i2c->data); udelay (20000); - if (readw (I2C_STAT) & I2C_STAT_NACK) { + if (readw (&i2c->stat) & I2C_STAT_NACK) { i2c_error = 1; } } else { @@ -91,28 +98,28 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
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->con); + while (readw (&i2c->stat) || (readw (&i2c->con) & I2C_CON_MST)) { udelay (10000); /* Have to clear pending interrupt to clear I2C_STAT */ - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c->stat); }
wait_for_bb (); /* set slave address */ - writew (devaddr, I2C_SA); + writew (devaddr, &i2c->sa); /* read one byte from slave */ - writew (1, I2C_CNT); + writew (1, &i2c->cnt); /* need stop bit here */ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, - I2C_CON); + &i2c->con);
status = wait_for_pin (); if (status & I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) - *value = readb (I2C_DATA); + *value = readb (&i2c->data); #else - *value = readw (I2C_DATA); + *value = readw (&i2c->data); #endif udelay (20000); } else { @@ -120,17 +127,17 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) }
if (!i2c_error) { - writew (I2C_CON_EN, I2C_CON); - while (readw (I2C_STAT) - || (readw (I2C_CON) & I2C_CON_MST)) { + writew (I2C_CON_EN, &i2c->con); + while (readw (&i2c->stat) + || (readw (&i2c->con) & I2C_CON_MST)) { udelay (10000); - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c->stat); } } } flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c->stat); + writew (0, &i2c->cnt); return i2c_error; }
@@ -143,12 +150,12 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) wait_for_bb ();
/* two bytes */ - writew (2, I2C_CNT); + writew (2, &i2c->cnt); /* set slave address */ - writew (devaddr, I2C_SA); + writew (devaddr, &i2c->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->con);
/* wait until state change */ status = wait_for_pin (); @@ -156,24 +163,78 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) 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->data); + writew (I2C_STAT_XRDY, &i2c->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->data); + writew (I2C_STAT_XRDY, &i2c->stat); } else { i2c_error = 1; } #else /* send out two bytes */ - writew ((value << 8) + regoffset, I2C_DATA); + writew ((value << 8) + regoffset, &i2c->data); #endif /* must have enough delay to allow BB bit to go low */ - udelay (50000); - if (readw (I2C_STAT) & I2C_STAT_NACK) { + udelay (1000); + if (readw (&i2c->stat) & I2C_STAT_NACK) { + i2c_error = 1; + } + } else { + i2c_error = 1; + } + + if (!i2c_error) { + int eout = 200; + + writew (I2C_CON_EN, &i2c->con); + while ((stat = readw (&i2c->stat)) || (readw (&i2c->con) & I2C_CON_MST)) { + udelay (1000); + /* have to read to clear intrrupt */ + writew (0xFFFF, &i2c->stat); + if(--eout == 0) /* better leave with error than hang */ + break; + } + } + flush_fifo(); + writew (0xFFFF, &i2c->stat); + writew (0, &i2c->cnt); + return i2c_error; +} + +/* Write just one byte (no reg offset) */ +static int i2c_write_byte_raw (u8 devaddr, u8 value) +{ + int i2c_error = 0; + u16 status, stat; + + /* wait until bus not busy */ + wait_for_bb (); + + /* one bytes */ + writew (1, &i2c->cnt); + /* set slave address */ + writew (devaddr, &i2c->sa); + /* stop bit needed here */ + writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_STP, &i2c->con); + + /* wait until state change */ + status = wait_for_pin (); + + if (status & I2C_STAT_XRDY) { + /* send out 1 byte */ + writeb (value, &i2c->data); + writew (I2C_STAT_XRDY, &i2c->stat); + + status = wait_for_pin (); + + /* must have enough delay to allow BB bit to go low */ + udelay (1000); + if (readw (&i2c->stat) & I2C_STAT_NACK) { i2c_error = 1; } } else { @@ -183,18 +244,18 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) 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->con); + while ((stat = readw (&i2c->stat)) || (readw (&i2c->con) & I2C_CON_MST)) { udelay (1000); /* have to read to clear intrrupt */ - writew (0xFFFF, I2C_STAT); + writew (0xFFFF, &i2c->stat); if(--eout == 0) /* better leave with error than hang */ break; } } flush_fifo(); - writew (0xFFFF, I2C_STAT); - writew (0, I2C_CNT); + writew (0xFFFF, &i2c->stat); + writew (0, &i2c->cnt); return i2c_error; }
@@ -205,14 +266,14 @@ static void flush_fifo(void) * you get a bus error */ while(1){ - stat = readw(I2C_STAT); + stat = readw(&i2c->stat); if(stat == I2C_STAT_RRDY){ #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) - readb(I2C_DATA); + readb(&i2c->data); #else - readw(I2C_DATA); + readw(&i2c->data); #endif - writew(I2C_STAT_RRDY,I2C_STAT); + writew(I2C_STAT_RRDY,&i2c->stat); udelay(1000); }else break; @@ -223,7 +284,7 @@ int i2c_probe (uchar chip) { int res = 1; /* default = fail */
- if (chip == readw (I2C_OA)) { + if (chip == readw (&i2c->oa)) { return res; }
@@ -231,27 +292,27 @@ int i2c_probe (uchar chip) wait_for_bb ();
/* try to read one byte */ - writew (1, I2C_CNT); + writew (1, &i2c->cnt); /* set slave address */ - writew (chip, I2C_SA); + writew (chip, &i2c->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-
con);
/* enough delay for the NACK bit set */ - udelay (50000); + udelay (1000);
- if (!(readw (I2C_STAT) & I2C_STAT_NACK)) { + if (!(readw (&i2c->stat) & I2C_STAT_NACK)) { res = 0; /* success case */ flush_fifo(); - writew(0xFFFF, I2C_STAT); + writew(0xFFFF, &i2c->stat); } else { - writew(0xFFFF, I2C_STAT); /* failue, clear sources*/ - writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */ + writew(0xFFFF, &i2c->stat); /* failue, clear sources*/ + writew (readw (&i2c->con) | I2C_CON_STP, &i2c->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->cnt); /* don't allow any more data in...we don't want it.*/ + writew(0xFFFF, &i2c->stat); return res; }
@@ -284,23 +345,34 @@ int i2c_write (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); + if (alen > 1 || alen < 0) { + 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 out of range\n"); return 1; }
- 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; + if (alen == 1) + for (i = 0; i < len; i++) + { + if (i2c_write_byte (chip, addr + i, buffer[i])) { + printf ("I2C write: I/O error\n"); + i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 1; + } + } + else if (alen == 0) + for (i = 0; i < len; i++) + { + if (i2c_write_byte_raw (chip, buffer[i])) { + printf ("I2C write: I/O error\n"); + i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 1; + } } - }
return 0; } @@ -310,17 +382,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); - udelay (50000); + writew(0xFFFF, &i2c->stat); /* clear current interruts...*/ + while ((stat = readw (&i2c->stat) & I2C_STAT_BB) && timeout--) { + writew (stat, &i2c->stat); + udelay (1000); }
if (timeout <= 0) { printf ("timed out in wait_for_bb: I2C_STAT=%x\n", - readw (I2C_STAT)); + readw (&i2c->stat)); } - writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/ + writew(0xFFFF, &i2c->stat); /* clear delayed stuff*/ }
static u16 wait_for_pin (void) @@ -330,7 +402,7 @@ static u16 wait_for_pin (void)
do { udelay (1000); - status = readw (I2C_STAT); + status = readw (&i2c->stat); } while ( !(status & (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | @@ -338,8 +410,55 @@ 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->stat)); + writew(0xFFFF, &i2c->stat); } return status; } + +int i2c_set_bus_num(unsigned int bus) +{ + if ((bus < 0) || (bus >= I2C_NUM_IF)) { + printf("Bad bus: %d\n", bus); + return -1; + } + +#ifdef CONFIG_OMAP34XX + if (bus == 2) + i2c = (i2c_t *)I2C_BASE3; + else +#endif + if (bus == 1) + i2c = (i2c_t *)I2C_BASE2; + else + i2c = (i2c_t *)I2C_BASE1; + + return 0; +} + +int i2c_get_bus_num(void) +{ +#ifdef CONFIG_OMAP34XX + if (i2c == (i2c_t *)I2C_BASE3) + return 2; + else +#endif + if (i2c == (i2c_t *)I2C_BASE2) + return 1; + else if (i2c == (i2c_t *)I2C_BASE1) + return 0; + else + return -1; +} + +int i2c_get_bus_speed() +{ + return 100000; +} + +int i2c_set_bus_speed(int speed) +{ + printf("Not yet implemented\n"); + return -1; +} + diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c index e90db7e..234fddf 100644 --- a/drivers/mmc/omap3_mmc.c +++ b/drivers/mmc/omap3_mmc.c @@ -62,6 +62,9 @@ void twl4030_mmc_config(void) { unsigned char data;
+ i2c_set_bus_num(0); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + data = DEV_GRP_P1; i2c_write(PWRMGT_ADDR_ID4, VMMC1_DEV_GRP, 1, &data, 1); data = VMMC1_VSEL_30; diff --git a/include/asm-arm/arch-omap3/i2c.h b/include/asm-arm/arch- omap3/i2c.h index 3937f35..9638abc 100644 --- a/include/asm-arm/arch-omap3/i2c.h +++ b/include/asm-arm/arch-omap3/i2c.h @@ -25,21 +25,24 @@
#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) +typedef struct i2c { + unsigned int rev; /* 0x00 */ + unsigned int ie; /* 0x04 */ + unsigned int stat; /* 0x08 */ + unsigned int iv; /* 0x0c */ + unsigned int res1; /* 0x10 */ + unsigned int buf; /* 0x14 */ + unsigned int cnt; /* 0x18 */ + unsigned int data; /* 0x1c */ + unsigned int sysc; /* 0x20 */ + unsigned int con; /* 0x24 */ + unsigned int oa; /* 0x28 */ + unsigned int sa; /* 0x2c */ + unsigned int psc; /* 0x30 */ + unsigned int scll; /* 0x34 */ + unsigned int sclh; /* 0x38 */ + unsigned int systest; /* 0x3c */ +} i2c_t;
/* I2C masks */
diff --git a/include/configs/omap3_overo.h b/include/configs/ omap3_overo.h index b2c42fa..d8f7a9e 100644 --- a/include/configs/omap3_overo.h +++ b/include/configs/omap3_overo.h @@ -103,6 +103,7 @@ "4m(kernel),-(fs)"
#define CONFIG_CMD_I2C /* I2C serial bus support */ +#define CONFIG_I2C_CMD_TREE /* New-style command interface */ #define CONFIG_CMD_MMC /* MMC support */ #define CONFIG_CMD_NAND /* NAND support */
@@ -113,6 +114,7 @@ #undef CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */ #undef CONFIG_CMD_NFS /* NFS support */
+#define CONFIG_I2C_MULTI_BUS #define CONFIG_SYS_NO_FLASH #define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_SYS_I2C_SLAVE 1

Hello Hugo,
Hugo Vincent wrote:
This patch improves I2C support on OMAP3 platforms, including supporting the second and third I2C controllers (mainline only supports the first controller), and supporting writes where alen=0 (i.e. no register address - this was needed for some I2C devices I needed to drive from u-boot).
Tested on Gumstix Overo with several I2C devices, on I2C1 and 3.
The multi-bus support is mostly from this patch: http://www.beagleboard.org/gitweb/?p=u-boot-arm.git;a=commit;h=52eddcd07c2e7...
Best regards, Hugo Vincent
Signed-off-by: Hugo Vincent hugo.vincent@gmail.com
diff --git a/board/omap3/common/power.c b/board/omap3/common/power.c index 4908e5b..efc5dd4 100644 --- a/board/omap3/common/power.c +++ b/board/omap3/common/power.c @@ -42,6 +42,7 @@ void power_init_r(void) unsigned char byte;
#ifdef CONFIG_DRIVER_OMAP34XX_I2C
- i2c_set_bus_num(0); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 16439ac..6332965 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -1324,6 +1324,7 @@ U_BOOT_CMD( #endif ); #endif /* CONFIG_I2C_CMD_TREE */ +#if !defined(CONFIG_I2C_CMD_TREE)
no longer needed, see commit:
d48eb5131d287f52bb85b4c58c8680a2e8e3b641
U_BOOT_CMD( imd, 4, 1, do_i2c_md, \ "i2c memory display", \ @@ -1378,6 +1379,7 @@ U_BOOT_CMD( " (valid chip values 50..57)\n" ); #endif +#endif /* !defined(CONFIG_I2C_CMD_TREE) */
#if defined(CONFIG_I2C_MUX)
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 6784603..424f172 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -1,7 +1,7 @@ /*
- Basic I2C functions
- Copyright (c) 2004 Texas Instruments
- Copyright (c) 2004, 2009 Texas Instruments
- This package is free software; you can redistribute it and/or
- modify it under the terms of the license found in the file
@@ -18,6 +18,7 @@
- Adapted for OMAP2420 I2C, r-woodruff2@ti.com
- Some additions by Hugo Vincent hugo.vincent@gmail.com June 2009
*/
#include <common.h>
@@ -25,40 +24,44 @@ #include <asm/arch/i2c.h> #include <asm/io.h>
+#ifdef CONFIG_OMAP34XX +#define I2C_NUM_IF 3 +#else +#define I2C_NUM_IF 2 +#endif
- static void wait_for_bb (void); static u16 wait_for_pin (void); static void flush_fifo(void);
+static i2c_t *i2c = (i2c_t *)I2C_DEFAULT_BASE;
- void i2c_init (int speed, int slaveadd)
^ Seems to me something is wrong with your patch, because here and on other places in your patch is a space, which I couldn;t find in the original file. Please check.
{
- u16 scl;
- writew(0x2, I2C_SYSC); /* for ES2 after soft reset */
- writew(0x2, &i2c->sysc); /* for ES2 after soft reset */ udelay(1000);
- writew(0x0, I2C_SYSC); /* will probably self clear but */
- writew(0x0, &i2c->sysc); /* will probably self clear but */
- if (readw (I2C_CON) & I2C_CON_EN) {
writew (0, I2C_CON);
udelay (50000);
- if (readw (&i2c->con) & I2C_CON_EN) {
writew (0, &i2c->con);
}udelay (10000);
- /* 12MHz I2C module clock */
- writew (0, I2C_PSC);
- speed = speed/1000; /* 100 or 400 */
- scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */
- writew (scl, I2C_SCLL);
- writew (scl, I2C_SCLH);
- /* Timings from TRM, tested with scope - 100 kHz standard speed */
- writew (23, &i2c->psc);
- writew (13, &i2c->scll);
- writew (15, &i2c->sclh); /* own address */
- writew (slaveadd, I2C_OA);
- writew (I2C_CON_EN, I2C_CON);
writew (slaveadd, &i2c->oa);
writew (I2C_CON_EN, &i2c->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);
udelay (1000); flush_fifo();I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c->ie);
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
writew (0xFFFF, &i2c->stat);
writew (0, &i2c->cnt); }
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
@@ -70,19 +77,19 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) wait_for_bb ();
/* one byte only */
- writew (1, I2C_CNT);
- writew (1, &i2c->cnt); /* set slave address */
- writew (devaddr, I2C_SA);
- writew (devaddr, &i2c->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-
con);
This lines are wrapped, please check.
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) { /* Important: have to use byte access */
writeb (regoffset, I2C_DATA);
udelay (20000);writeb (regoffset, &i2c->data);
if (readw (I2C_STAT) & I2C_STAT_NACK) {
}if (readw (&i2c->stat) & I2C_STAT_NACK) { i2c_error = 1;
no brackets necessary.
} else { @@ -91,28 +98,28 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
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->con);
while (readw (&i2c->stat) || (readw (&i2c->con) & I2C_CON_MST)) { udelay (10000); /* Have to clear pending interrupt to clear I2C_STAT */
writew (0xFFFF, I2C_STAT);
writew (0xFFFF, &i2c->stat);
}
wait_for_bb (); /* set slave address */
writew (devaddr, I2C_SA);
/* read one byte from slave */writew (devaddr, &i2c->sa);
writew (1, I2C_CNT);
/* need stop bit here */ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,writew (1, &i2c->cnt);
I2C_CON);
&i2c->con);
status = wait_for_pin (); if (status & I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
*value = readb (I2C_DATA);
#else*value = readb (&i2c->data);
*value = readw (I2C_DATA);
#endif udelay (20000); } else {*value = readw (&i2c->data);
@@ -120,17 +127,17 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) }
if (!i2c_error) {
writew (I2C_CON_EN, I2C_CON);
while (readw (I2C_STAT)
|| (readw (I2C_CON) & I2C_CON_MST)) {
writew (I2C_CON_EN, &i2c->con);
while (readw (&i2c->stat)
|| (readw (&i2c->con) & I2C_CON_MST)) { udelay (10000);
writew (0xFFFF, I2C_STAT);
} } flush_fifo();writew (0xFFFF, &i2c->stat); }
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
- writew (0xFFFF, &i2c->stat);
- writew (0, &i2c->cnt); return i2c_error; }
@@ -143,12 +150,12 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) wait_for_bb ();
/* two bytes */
- writew (2, I2C_CNT);
- writew (2, &i2c->cnt); /* set slave address */
- writew (devaddr, I2C_SA);
- writew (devaddr, &i2c->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->con);
/* wait until state change */ status = wait_for_pin ();
@@ -156,24 +163,78 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) 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->data);
writew (I2C_STAT_XRDY, &i2c->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->data);
} else { i2c_error = 1; } #else /* send out two bytes */writew (I2C_STAT_XRDY, &i2c->stat);
writew ((value << 8) + regoffset, I2C_DATA);
#endif /* must have enough delay to allow BB bit to go low */writew ((value << 8) + regoffset, &i2c->data);
udelay (50000);
if (readw (I2C_STAT) & I2C_STAT_NACK) {
udelay (1000);
if (readw (&i2c->stat) & I2C_STAT_NACK) {
i2c_error = 1;
}
please no brackets
- } else {
i2c_error = 1;
- }
here too, no brackets. Please check everywhere.
- if (!i2c_error) {
int eout = 200;
writew (I2C_CON_EN, &i2c->con);
while ((stat = readw (&i2c->stat)) || (readw (&i2c->con) &
I2C_CON_MST)) {
line wrapped, please check your mailer.
udelay (1000);
/* have to read to clear intrrupt */
writew (0xFFFF, &i2c->stat);
if(--eout == 0) /* better leave with error than hang */
break;
}
- }
- flush_fifo();
- writew (0xFFFF, &i2c->stat);
- writew (0, &i2c->cnt);
- return i2c_error;
+}
+/* Write just one byte (no reg offset) */ +static int i2c_write_byte_raw (u8 devaddr, u8 value) +{
- int i2c_error = 0;
- u16 status, stat;
- /* wait until bus not busy */
- wait_for_bb ();
- /* one bytes */
- writew (1, &i2c->cnt);
- /* set slave address */
- writew (devaddr, &i2c->sa);
- /* stop bit needed here */
- writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c->con);
- /* wait until state change */
- status = wait_for_pin ();
- if (status & I2C_STAT_XRDY) {
/* send out 1 byte */
writeb (value, &i2c->data);
writew (I2C_STAT_XRDY, &i2c->stat);
status = wait_for_pin ();
/* must have enough delay to allow BB bit to go low */
udelay (1000);
} } else {if (readw (&i2c->stat) & I2C_STAT_NACK) { i2c_error = 1;
@@ -183,18 +244,18 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) if (!i2c_error) { int eout = 200;
writew (I2C_CON_EN, I2C_CON);
while ((stat = readw (I2C_STAT)) || (readw (I2C_CON) &
I2C_CON_MST)) {
line wrapped
writew (I2C_CON_EN, &i2c->con);
while ((stat = readw (&i2c->stat)) || (readw (&i2c->con) &
I2C_CON_MST)) {
line wrapped
udelay (1000); /* have to read to clear intrrupt */
writew (0xFFFF, I2C_STAT);
} } flush_fifo();writew (0xFFFF, &i2c->stat); if(--eout == 0) /* better leave with error than hang */ break;
- writew (0xFFFF, I2C_STAT);
- writew (0, I2C_CNT);
- writew (0xFFFF, &i2c->stat);
- writew (0, &i2c->cnt); return i2c_error; }
^ no space.
@@ -205,14 +266,14 @@ static void flush_fifo(void) * you get a bus error */ while(1){
stat = readw(I2C_STAT);
if(stat == I2C_STAT_RRDY){ #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)stat = readw(&i2c->stat);
readb(I2C_DATA);
#elsereadb(&i2c->data);
readw(I2C_DATA);
#endifreadw(&i2c->data);
writew(I2C_STAT_RRDY,I2C_STAT);
}else break;writew(I2C_STAT_RRDY,&i2c->stat); udelay(1000);
@@ -223,7 +284,7 @@ int i2c_probe (uchar chip) { int res = 1; /* default = fail */
- if (chip == readw (I2C_OA)) {
- if (chip == readw (&i2c->oa)) { return res; }
@@ -231,27 +292,27 @@ int i2c_probe (uchar chip) wait_for_bb ();
/* try to read one byte */
- writew (1, I2C_CNT);
- writew (1, &i2c->cnt); /* set slave address */
- writew (chip, I2C_SA);
- writew (chip, &i2c->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-
con);
lines wrapped
/* enough delay for the NACK bit set */
- udelay (50000);
- udelay (1000);
- if (!(readw (I2C_STAT) & I2C_STAT_NACK)) {
- if (!(readw (&i2c->stat) & I2C_STAT_NACK)) { res = 0; /* success case */ flush_fifo();
writew(0xFFFF, I2C_STAT);
} else {writew(0xFFFF, &i2c->stat);
writew(0xFFFF, I2C_STAT); /* failue, clear sources*/
writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
writew(0xFFFF, &i2c->stat); /* failue, clear sources*/
writew (readw (&i2c->con) | I2C_CON_STP, &i2c->con); /* finish up
xfer */
line wrapped
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->cnt); /* don't allow any more data in...we don't
want it.*/
lines wrapped
- writew(0xFFFF, &i2c->stat); return res; }
@@ -284,23 +345,34 @@ int i2c_write (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);
if (alen > 1 || alen < 0) {
printf ("I2C write: addr len %d not supported\n", alen);
return 1; }
if (addr + len > 256) {
printf ("I2C read: address out of range\n");
return 1; }printf ("I2C write: address out of range\n");
- 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;
- if (alen == 1)
for (i = 0; i < len; i++)
{
if (i2c_write_byte (chip, addr + i, buffer[i])) {
printf ("I2C write: I/O error\n");
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
- else if (alen == 0)
for (i = 0; i < len; i++)
{
if (i2c_write_byte_raw (chip, buffer[i])) {
printf ("I2C write: I/O error\n");
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}}
}
return 0; }
@@ -310,17 +382,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);
udelay (50000);
writew(0xFFFF, &i2c->stat); /* clear current interruts...*/
while ((stat = readw (&i2c->stat) & I2C_STAT_BB) && timeout--) {
writew (stat, &i2c->stat);
udelay (1000);
}
if (timeout <= 0) { printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
readw (I2C_STAT));
}readw (&i2c->stat));
- writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/
writew(0xFFFF, &i2c->stat); /* clear delayed stuff*/ }
static u16 wait_for_pin (void)
@@ -330,7 +402,7 @@ static u16 wait_for_pin (void)
do { udelay (1000);
status = readw (I2C_STAT);
} while ( !(status & (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |status = readw (&i2c->stat);
@@ -338,8 +410,55 @@ 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->stat));
} return status; }writew(0xFFFF, &i2c->stat);
+int i2c_set_bus_num(unsigned int bus) +{
- if ((bus < 0) || (bus >= I2C_NUM_IF)) {
printf("Bad bus: %d\n", bus);
return -1;
- }
+#ifdef CONFIG_OMAP34XX
- if (bus == 2)
i2c = (i2c_t *)I2C_BASE3;
- else
+#endif
- if (bus == 1)
i2c = (i2c_t *)I2C_BASE2;
- else
i2c = (i2c_t *)I2C_BASE1;
- return 0;
+}
+int i2c_get_bus_num(void) +{ +#ifdef CONFIG_OMAP34XX
- if (i2c == (i2c_t *)I2C_BASE3)
return 2;
- else
+#endif
- if (i2c == (i2c_t *)I2C_BASE2)
return 1;
- else if (i2c == (i2c_t *)I2C_BASE1)
return 0;
- else
return -1;
+}
+int i2c_get_bus_speed() +{
- return 100000;
+}
+int i2c_set_bus_speed(int speed) +{
- printf("Not yet implemented\n");
- return -1;
+}
diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c index e90db7e..234fddf 100644 --- a/drivers/mmc/omap3_mmc.c +++ b/drivers/mmc/omap3_mmc.c @@ -62,6 +62,9 @@ void twl4030_mmc_config(void) { unsigned char data;
- i2c_set_bus_num(0);
- i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
- data = DEV_GRP_P1; i2c_write(PWRMGT_ADDR_ID4, VMMC1_DEV_GRP, 1, &data, 1); data = VMMC1_VSEL_30;
diff --git a/include/asm-arm/arch-omap3/i2c.h b/include/asm-arm/arch- omap3/i2c.h index 3937f35..9638abc 100644 --- a/include/asm-arm/arch-omap3/i2c.h +++ b/include/asm-arm/arch-omap3/i2c.h @@ -25,21 +25,24 @@
#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) +typedef struct i2c {
unsigned int rev; /* 0x00 */
please use tab for identation.
unsigned int ie; /* 0x04 */
unsigned int stat; /* 0x08 */
unsigned int iv; /* 0x0c */
unsigned int res1; /* 0x10 */
unsigned int buf; /* 0x14 */
unsigned int cnt; /* 0x18 */
unsigned int data; /* 0x1c */
unsigned int sysc; /* 0x20 */
unsigned int con; /* 0x24 */
unsigned int oa; /* 0x28 */
unsigned int sa; /* 0x2c */
unsigned int psc; /* 0x30 */
unsigned int scll; /* 0x34 */
unsigned int sclh; /* 0x38 */
unsigned int systest; /* 0x3c */
+} i2c_t;
/* I2C masks */
diff --git a/include/configs/omap3_overo.h b/include/configs/ omap3_overo.h index b2c42fa..d8f7a9e 100644 --- a/include/configs/omap3_overo.h +++ b/include/configs/omap3_overo.h @@ -103,6 +103,7 @@ "4m(kernel),-(fs)"
#define CONFIG_CMD_I2C /* I2C serial bus support */ +#define CONFIG_I2C_CMD_TREE /* New-style command interface */
no longer needed, please remove.
#define CONFIG_CMD_MMC /* MMC support */ #define CONFIG_CMD_NAND /* NAND support */
@@ -113,6 +114,7 @@ #undef CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */ #undef CONFIG_CMD_NFS /* NFS support */
+#define CONFIG_I2C_MULTI_BUS #define CONFIG_SYS_NO_FLASH #define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_SYS_I2C_SLAVE 1
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
bye, Heiko

Hugo Vincent wrote:
Hi everyone,
This patch improves I2C support on OMAP3 platforms, including supporting the second and third I2C controllers (mainline only supports the first controller), and supporting writes where alen=0 (i.e. no register address - this was needed for some I2C devices I needed to drive from u-boot).
Tested on Gumstix Overo with several I2C devices, on I2C1 and 3.
The multi-bus support is mostly from this patch: http://www.beagleboard.org/gitweb/?p=u-boot-arm.git;a=commit;h=52eddcd07c2e7...
Best regards, Hugo Vincent
Signed-off-by: Hugo Vincent hugo.vincent@gmail.com
Does anybody have an up to date version of this patch? Seems we need it for Beagle Zippy, too.
Thanks
Dirk

Dirk Behme wrote:
Hugo Vincent wrote:
Hi everyone,
This patch improves I2C support on OMAP3 platforms, including supporting the second and third I2C controllers (mainline only supports the first controller), and supporting writes where alen=0 (i.e. no register address - this was needed for some I2C devices I needed to drive from u-boot).
Tested on Gumstix Overo with several I2C devices, on I2C1 and 3.
The multi-bus support is mostly from this patch: http://www.beagleboard.org/gitweb/?p=u-boot-arm.git;a=commit;h=52eddcd07c2e7...
Best regards, Hugo Vincent
Signed-off-by: Hugo Vincent hugo.vincent@gmail.com
Does anybody have an up to date version of this patch? Seems we need it for Beagle Zippy, too.
Thanks for the pointer. I have cherry picked this commit and am testing it now. I will post it once it is done, likely today. Tom
Thanks
Dirk
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Tom Rix wrote:
Dirk Behme wrote:
Hugo Vincent wrote:
Hi everyone,
This patch improves I2C support on OMAP3 platforms, including supporting the second and third I2C controllers (mainline only supports the first controller), and supporting writes where alen=0 (i.e. no register address - this was needed for some I2C devices I needed to drive from u-boot).
Tested on Gumstix Overo with several I2C devices, on I2C1 and 3.
The multi-bus support is mostly from this patch: http://www.beagleboard.org/gitweb/?p=u-boot-arm.git;a=commit;h=52eddcd07c2e7...
Best regards, Hugo Vincent
Signed-off-by: Hugo Vincent hugo.vincent@gmail.com
Does anybody have an up to date version of this patch? Seems we need it for Beagle Zippy, too.
Thanks for the pointer. I have cherry picked this commit and am testing it now. I will post it once it is done, likely today.
I'm currently working on (compile tested only) patch in attachment.
Cheers
Dirk
Subject: [PATCH] OMAP2/3: I2C: Add support for second and third bus From: Dirk Behme dirk.behme@googlemail.com
Add support to use second and on OMAP3 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 dirk.behme@googlemail.com ---
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-omap3/i2c.h | 54 +++++++++--- 2 files changed, 138 insertions(+), 82 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,43 @@
#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 */ +}; + +#ifdef CONFIG_OMAP34XX +#define I2C_BUS_MAX 3 +#else +#define I2C_BUS_MAX 2 +#endif
/* I2C masks */
@@ -181,4 +203,6 @@ #define I2C_PSC_MAX 0x0f #define I2C_PSC_MIN 0x00
+extern int i2c_set_bus_num(unsigned int); + #endif /* _I2C_H_ */
participants (4)
-
Dirk Behme
-
Heiko Schocher
-
Hugo Vincent
-
Tom Rix