diff options
author | Wolfgang Denk <wd@denx.de> | 2012-02-11 22:05:13 +0100 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2012-02-11 22:05:13 +0100 |
commit | 6e4c1da86e77576476b566977305ddd82f9e6b8c (patch) | |
tree | 9aae79ccdf1c55f7999dbd71f5dd137c263266f8 | |
parent | b75190debab35f3a138774d0d41595493574d112 (diff) | |
parent | b4116ede36da628a517a94d6cba9dba4a02104a4 (diff) |
Merge branch 'master' of /home/wd/git/u-boot/custodians
* 'master' of /home/wd/git/u-boot/custodians:
ARM: AM33XX: Add i2c support
ARM: AM33XX: Add AM33XX I2C driver support
ARM: I2C: I2C Multi byte address support
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/clock.c | 5 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-am33xx/common_def.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-am33xx/cpu.h | 3 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-am33xx/i2c.h | 81 | ||||
-rw-r--r-- | board/ti/am335x/evm.c | 7 | ||||
-rw-r--r-- | board/ti/am335x/mux.c | 13 | ||||
-rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 475 | ||||
-rw-r--r-- | drivers/i2c/omap24xx_i2c.h | 2 | ||||
-rw-r--r-- | include/configs/am335x_evm.h | 9 |
9 files changed, 421 insertions, 175 deletions
diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c index 98cfd938140..bbb9c1353f2 100644 --- a/arch/arm/cpu/armv7/am33xx/clock.c +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -113,6 +113,11 @@ static void enable_per_clocks(void) writel(PRCM_MOD_EN, &cmper->mmc0clkctrl); while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN) ; + + /* i2c0 */ + writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl); + while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN) + ; } static void mpu_pll_config(void) diff --git a/arch/arm/include/asm/arch-am33xx/common_def.h b/arch/arm/include/asm/arch-am33xx/common_def.h index 767932daea8..aa3b5545368 100644 --- a/arch/arm/include/asm/arch-am33xx/common_def.h +++ b/arch/arm/include/asm/arch-am33xx/common_def.h @@ -18,5 +18,6 @@ extern void enable_uart0_pin_mux(void); extern void enable_mmc0_pin_mux(void); +extern void enable_i2c0_pin_mux(void); #endif/*__COMMON_DEF_H__ */ diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h b/arch/arm/include/asm/arch-am33xx/cpu.h index 25558a2b2c8..cd002e632d2 100644 --- a/arch/arm/include/asm/arch-am33xx/cpu.h +++ b/arch/arm/include/asm/arch-am33xx/cpu.h @@ -95,7 +95,8 @@ struct cm_wkuppll { unsigned int divm2dpllper; /* offset 0xAC */ unsigned int resv11[1]; unsigned int wkup_uart0ctrl; /* offset 0xB4 */ - unsigned int resv12[8]; + unsigned int wkup_i2c0ctrl; /* offset 0xB8 */ + unsigned int resv12[7]; unsigned int divm6dpllcore; /* offset 0xD8 */ }; diff --git a/arch/arm/include/asm/arch-am33xx/i2c.h b/arch/arm/include/asm/arch-am33xx/i2c.h new file mode 100644 index 00000000000..366e2bbec55 --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/i2c.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2012 + * Texas Instruments, <www.ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _I2C_H_ +#define _I2C_H_ + +#define I2C_BASE1 0x44E0B000 +#define I2C_BASE2 0x4802A000 +#define I2C_BASE3 0x4819C000 +#define I2C_BUS_MAX 3 + +#define I2C_DEFAULT_BASE I2C_BASE1 + +struct i2c { + unsigned short revnb_lo; /* 0x00 */ + unsigned short res1; + unsigned short revnb_hi; /* 0x04 */ + unsigned short res2[13]; + unsigned short sysc; /* 0x20 */ + unsigned short res3; + unsigned short irqstatus_raw; /* 0x24 */ + unsigned short res4; + unsigned short stat; /* 0x28 */ + unsigned short res5; + unsigned short ie; /* 0x2C */ + unsigned short res6; + unsigned short irqenable_clr; /* 0x30 */ + unsigned short res7; + unsigned short iv; /* 0x34 */ + unsigned short res8[45]; + unsigned short syss; /* 0x90 */ + unsigned short res9; + unsigned short buf; /* 0x94 */ + unsigned short res10; + unsigned short cnt; /* 0x98 */ + unsigned short res11; + unsigned short data; /* 0x9C */ + unsigned short res13; + unsigned short res14; /* 0xA0 */ + unsigned short res15; + unsigned short con; /* 0xA4 */ + unsigned short res16; + unsigned short oa; /* 0xA8 */ + unsigned short res17; + unsigned short sa; /* 0xAC */ + unsigned short res18; + unsigned short psc; /* 0xB0 */ + unsigned short res19; + unsigned short scll; /* 0xB4 */ + unsigned short res20; + unsigned short sclh; /* 0xB8 */ + unsigned short res21; + unsigned short systest; /* 0xBC */ + unsigned short res22; + unsigned short bufstat; /* 0xC0 */ + unsigned short res23; +}; + +#define I2C_IP_CLK 48000000 +#define I2C_INTERNAL_SAMLPING_CLK 12000000 + +#endif /* _I2C_H_ */ diff --git a/board/ti/am335x/evm.c b/board/ti/am335x/evm.c index 6a9f788299f..13dc60361a2 100644 --- a/board/ti/am335x/evm.c +++ b/board/ti/am335x/evm.c @@ -18,6 +18,7 @@ #include <asm/arch/hardware.h> #include <asm/arch/common_def.h> #include <serial.h> +#include <i2c.h> DECLARE_GLOBAL_DATA_PTR; @@ -42,6 +43,12 @@ int init_basic_setup(void) int board_init(void) { enable_uart0_pin_mux(); + +#ifdef CONFIG_I2C + enable_i2c0_pin_mux(); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + init_basic_setup(); return 0; diff --git a/board/ti/am335x/mux.c b/board/ti/am335x/mux.c index 4cb0cdf361a..9ccb43642b3 100644 --- a/board/ti/am335x/mux.c +++ b/board/ti/am335x/mux.c @@ -272,6 +272,14 @@ static struct module_pin_mux mmc0_pin_mux[] = { }; #endif +static struct module_pin_mux i2c0_pin_mux[] = { + {OFFSET(i2c0_sda), (MODE(0) | RXACTIVE | + PULLUDEN | SLEWCTRL)}, /* I2C_DATA */ + {OFFSET(i2c0_scl), (MODE(0) | RXACTIVE | + PULLUDEN | SLEWCTRL)}, /* I2C_SCLK */ + {-1}, +}; + /* * Configure the pin mux for the module */ @@ -297,3 +305,8 @@ void enable_mmc0_pin_mux(void) configure_module_pin_mux(mmc0_pin_mux); } #endif + +void enable_i2c0_pin_mux(void) +{ + configure_module_pin_mux(i2c0_pin_mux); +} diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index a7ffd95d5d7..f06af02ba31 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -29,10 +29,11 @@ DECLARE_GLOBAL_DATA_PTR; -#define I2C_TIMEOUT 1000 +#define I2C_STAT_TIMEO (1 << 31) +#define I2C_TIMEOUT 10 -static void wait_for_bb(void); -static u16 wait_for_pin(void); +static u32 wait_for_bb(void); +static u32 wait_for_status_mask(u16 mask); static void flush_fifo(void); /* @@ -50,7 +51,6 @@ void i2c_init(int speed, int slaveadd) int psc, fsscll, fssclh; int hsscll = 0, hssclh = 0; u32 scll, sclh; - int timeout = I2C_TIMEOUT; /* Only handle standard, fast and high speeds */ if ((speed != OMAP_I2C_STANDARD) && @@ -112,24 +112,14 @@ void i2c_init(int speed, int slaveadd) sclh = (unsigned int)fssclh; } + if (gd->flags & GD_FLG_RELOC) + bus_initialized[current_bus] = 1; + 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 */ - udelay(1000); - - writew(I2C_CON_EN, &i2c_base->con); - while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) { - if (timeout <= 0) { - puts("ERROR: Timeout in soft-reset\n"); - return; - } - udelay(1000); - } - - writew(0, &i2c_base->con); writew(psc, &i2c_base->psc); writew(scll, &i2c_base->scll); writew(sclh, &i2c_base->sclh); @@ -145,81 +135,6 @@ void i2c_init(int speed, int slaveadd) flush_fifo(); 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) -{ - int i2c_error = 0; - u16 status; - - /* wait until bus not busy */ - wait_for_bb(); - - /* one byte only */ - writew(1, &i2c_base->cnt); - /* set slave address */ - 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); - - /* send register offset */ - while (1) { - status = wait_for_pin(); - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - goto read_exit; - } - if (status & I2C_STAT_XRDY) { - /* Important: have to use byte access */ - writeb(regoffset, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; - } - } - - /* set slave address */ - writew(devaddr, &i2c_base->sa); - /* read one byte from slave */ - writew(1, &i2c_base->cnt); - /* need stop bit here */ - writew(I2C_CON_EN | I2C_CON_MST | - I2C_CON_STT | I2C_CON_STP, - &i2c_base->con); - - /* receive data */ - while (1) { - status = wait_for_pin(); - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - goto read_exit; - } - if (status & I2C_STAT_RRDY) { -#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) - *value = readb(&i2c_base->data); -#else - *value = readw(&i2c_base->data); -#endif - writew(I2C_STAT_RRDY, &i2c_base->stat); - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; - } - } - -read_exit: - flush_fifo(); - writew(0xFFFF, &i2c_base->stat); - writew(0, &i2c_base->cnt); - return i2c_error; } static void flush_fifo(void) @@ -232,7 +147,7 @@ static void flush_fifo(void) stat = readw(&i2c_base->stat); 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); @@ -246,32 +161,42 @@ static void flush_fifo(void) int i2c_probe(uchar chip) { - u16 status; + u32 status; int res = 1; /* default = fail */ if (chip == readw(&i2c_base->oa)) return res; /* wait until bus not busy */ - wait_for_bb(); + status = wait_for_bb(); + /* exit on BUS busy */ + if (status & I2C_STAT_TIMEO) + return res; /* try to write one byte */ writew(1, &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); - - status = wait_for_pin(); - - /* check for ACK (!NAK) */ - if (!(status & I2C_STAT_NACK)) - res = 0; - - /* abort transfer (force idle state) */ - writew(0, &i2c_base->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(9000); + + if (!(readw(&i2c_base->stat) & I2C_STAT_NACK)) { + res = 0; /* success case */ + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + } else { + /* failure, clear sources*/ + writew(0xFFFF, &i2c_base->stat); + /* finish up xfer */ + writew(readw(&i2c_base->con) | I2C_CON_STP, &i2c_base->con); + status = wait_for_bb(); + /* exit on BUS busy */ + if (status & I2C_STAT_TIMEO) + return res; + } flush_fifo(); /* don't allow any more data in... we don't want it. */ writew(0, &i2c_base->cnt); @@ -281,111 +206,315 @@ int i2c_probe(uchar chip) int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - int i; + int i2c_error = 0, i; + u32 status; - if (alen > 1) { - printf("I2C read: addr len %d not supported\n", alen); + if ((alen > 2) || (alen < 0)) + return 1; + + if (alen < 2) { + if (addr + len > 256) + return 1; + } else if (addr + len > 0xFFFF) { return 1; } - if (addr + len > 256) { - puts("I2C read: address out of range\n"); + /* wait until bus not busy */ + status = wait_for_bb(); + + /* exit on BUS busy */ + if (status & I2C_STAT_TIMEO) return 1; + + writew((alen & 0xFF), &i2c_base->cnt); + /* set slave address */ + writew(chip, &i2c_base->sa); + /* Clear the Tx & Rx FIFOs */ + writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR | + I2C_TXFIFO_CLEAR), &i2c_base->buf); + /* no stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX | + I2C_CON_STT, &i2c_base->con); + + /* wait for Transmit ready condition */ + status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK); + + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) + i2c_error = 1; + + if (!i2c_error) { + if (status & I2C_STAT_XRDY) { + switch (alen) { + case 2: + /* Send address MSByte */ +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + writew(((addr >> 8) & 0xFF), &i2c_base->data); + + /* Clearing XRDY event */ + writew((status & I2C_STAT_XRDY), + &i2c_base->stat); + /* wait for Transmit ready condition */ + status = wait_for_status_mask(I2C_STAT_XRDY | + I2C_STAT_NACK); + + if (status & (I2C_STAT_NACK | + I2C_STAT_TIMEO)) { + i2c_error = 1; + break; + } +#endif + case 1: +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + /* Send address LSByte */ + writew((addr & 0xFF), &i2c_base->data); +#else + /* Send address Short word */ + writew((addr & 0xFFFF), &i2c_base->data); +#endif + /* Clearing XRDY event */ + writew((status & I2C_STAT_XRDY), + &i2c_base->stat); + /*wait for Transmit ready condition */ + status = wait_for_status_mask(I2C_STAT_ARDY | + I2C_STAT_NACK); + + if (status & (I2C_STAT_NACK | + I2C_STAT_TIMEO)) { + i2c_error = 1; + break; + } + } + } else + i2c_error = 1; } - for (i = 0; i < len; i++) { - 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; + /* Wait for ARDY to set */ + status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK + | I2C_STAT_AL); + + if (!i2c_error) { + /* set slave address */ + writew(chip, &i2c_base->sa); + writew((len & 0xFF), &i2c_base->cnt); + /* Clear the Tx & Rx FIFOs */ + writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR | + I2C_TXFIFO_CLEAR), &i2c_base->buf); + /* need stop bit here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, + &i2c_base->con); + + for (i = 0; i < len; i++) { + /* wait for Receive condition */ + status = wait_for_status_mask(I2C_STAT_RRDY | + I2C_STAT_NACK); + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) { + i2c_error = 1; + break; + } + + if (status & I2C_STAT_RRDY) { +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + buffer[i] = readb(&i2c_base->data); +#else + *((u16 *)&buffer[i]) = + readw(&i2c_base->data) & 0xFFFF; + i++; +#endif + writew((status & I2C_STAT_RRDY), + &i2c_base->stat); + udelay(1000); + } else { + i2c_error = 1; + } } } + /* Wait for ARDY to set */ + status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK + | I2C_STAT_AL); + + if (i2c_error) { + writew(0, &i2c_base->con); + return 1; + } + + writew(I2C_CON_EN, &i2c_base->con); + + while (readw(&i2c_base->stat) + || (readw(&i2c_base->con) & I2C_CON_MST)) { + udelay(10000); + writew(0xFFFF, &i2c_base->stat); + } + + writew(I2C_CON_EN, &i2c_base->con); + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + writew(0, &i2c_base->cnt); + return 0; } 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 write: addr len %d not supported\n", alen); + int i, i2c_error = 0; + u32 status; + u16 writelen; + + if (alen > 2) return 1; - } - if (addr + len > 256) { - printf("I2C write: address 0x%x + 0x%x out of range\n", - addr, len); + if (alen < 2) { + if (addr + len > 256) + return 1; + } else if (addr + len > 0xFFFF) { return 1; } /* wait until bus not busy */ - wait_for_bb(); + status = 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); + /* exiting on BUS busy */ + if (status & I2C_STAT_TIMEO) + return 1; + + writelen = (len & 0xFFFF) + alen; + + /* two bytes */ + writew((writelen & 0xFFFF), &i2c_base->cnt); + /* Clear the Tx & Rx FIFOs */ + writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR | + I2C_TXFIFO_CLEAR), &i2c_base->buf); /* 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(); + /* wait for Transmit ready condition */ + status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK); - if (status == 0 || status & I2C_STAT_NACK) { + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) 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; - } + if (!i2c_error) { + if (status & I2C_STAT_XRDY) { + switch (alen) { +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + case 2: + /* send out MSB byte */ + writeb(((addr >> 8) & 0xFF), &i2c_base->data); +#else + writeb((addr & 0xFFFF), &i2c_base->data); + break; +#endif + /* Clearing XRDY event */ + writew((status & I2C_STAT_XRDY), + &i2c_base->stat); + /*waiting for Transmit ready * condition */ + status = wait_for_status_mask(I2C_STAT_XRDY | + I2C_STAT_NACK); + + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) { + i2c_error = 1; + break; + } + case 1: +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + /* send out MSB byte */ + writeb((addr & 0xFF), &i2c_base->data); +#else + writew(((buffer[0] << 8) | (addr & 0xFF)), + &i2c_base->data); +#endif + } - /* address phase is over, now write data */ - for (i = 0; i < len; i++) { - status = wait_for_pin(); + /* Clearing XRDY event */ + writew((status & I2C_STAT_XRDY), &i2c_base->stat); + } + + /* waiting for Transmit ready condition */ + status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK); - if (status == 0 || status & I2C_STAT_NACK) { + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) i2c_error = 1; - printf("i2c error waiting for data ACK (status=0x%x)\n", - status); - goto write_exit; + + if (!i2c_error) { + for (i = ((alen > 1) ? 0 : 1); i < len; i++) { + if (status & I2C_STAT_XRDY) { +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_AM33XX) + writeb((buffer[i] & 0xFF), + &i2c_base->data); +#else + writew((((buffer[i] << 8) | + buffer[i + 1]) & 0xFFFF), + &i2c_base->data); + i++; +#endif + } else + i2c_error = 1; + /* Clearing XRDY event */ + writew((status & I2C_STAT_XRDY), + &i2c_base->stat); + /* waiting for XRDY condition */ + status = wait_for_status_mask( + I2C_STAT_XRDY | + I2C_STAT_ARDY | + I2C_STAT_NACK); + if (status & (I2C_STAT_NACK | + I2C_STAT_TIMEO)) { + i2c_error = 1; + break; + } + if (status & I2C_STAT_ARDY) + break; + } } + } - 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; + status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK | + I2C_STAT_AL); + + if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) + i2c_error = 1; + + if (i2c_error) { + writew(0, &i2c_base->con); + return 1; + } + + if (!i2c_error) { + int eout = 200; + + writew(I2C_CON_EN, &i2c_base->con); + while ((status = readw(&i2c_base->stat)) || + (readw(&i2c_base->con) & I2C_CON_MST)) { + udelay(1000); + /* have to read to clear intrrupt */ + writew(0xFFFF, &i2c_base->stat); + if (--eout == 0) + /* better leave with error than hang */ + break; } } -write_exit: flush_fifo(); writew(0xFFFF, &i2c_base->stat); - return i2c_error; + writew(0, &i2c_base->cnt); + return 0; } -static void wait_for_bb(void) +static u32 wait_for_bb(void) { int timeout = I2C_TIMEOUT; - u16 stat; + u32 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); @@ -394,30 +523,28 @@ static void wait_for_bb(void) if (timeout <= 0) { printf("timed out in wait_for_bb: I2C_STAT=%x\n", readw(&i2c_base->stat)); + stat |= I2C_STAT_TIMEO; } writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ + return stat; } -static u16 wait_for_pin(void) +static u32 wait_for_status_mask(u16 mask) { - u16 status; + u32 status; int timeout = I2C_TIMEOUT; do { 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--); + } while (!(status & mask) && timeout--); if (timeout <= 0) { - printf("timed out in wait_for_pin: I2C_STAT=%x\n", + printf("timed out in wait_for_status_mask: I2C_STAT=%x\n", readw(&i2c_base->stat)); writew(0xFFFF, &i2c_base->stat); - status = 0; + status |= I2C_STAT_TIMEO; } - return status; } diff --git a/drivers/i2c/omap24xx_i2c.h b/drivers/i2c/omap24xx_i2c.h index 1f38c232d16..9a0b126b387 100644 --- a/drivers/i2c/omap24xx_i2c.h +++ b/drivers/i2c/omap24xx_i2c.h @@ -60,7 +60,9 @@ /* I2C Buffer Configuration Register (I2C_BUF): */ #define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */ +#define I2C_RXFIFO_CLEAR (1 << 14) /* RX FIFO Clear */ #define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */ +#define I2C_TXFIFO_CLEAR (1 << 6) /* TX FIFO clear */ /* I2C Configuration Register (I2C_CON): */ diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 2cea1f46127..6683b3ec29a 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -103,6 +103,14 @@ #define CONFIG_SYS_NS16550_CLK (48000000) #define CONFIG_SYS_NS16550_COM1 0x44e09000 /* Base EVM has UART0 */ +/* I2C Configuration */ +#define CONFIG_I2C +#define CONFIG_CMD_I2C +#define CONFIG_HARD_I2C +#define CONFIG_SYS_I2C_SPEED 100000 +#define CONFIG_SYS_I2C_SLAVE 1 +#define CONFIG_DRIVER_OMAP24XX_I2C + #define CONFIG_BAUDRATE 115200 #define CONFIG_SYS_BAUDRATE_TABLE { 110, 300, 600, 1200, 2400, \ 4800, 9600, 14400, 19200, 28800, 38400, 56000, 57600, 115200 } @@ -131,6 +139,7 @@ #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img" #define CONFIG_SPL_MMC_SUPPORT #define CONFIG_SPL_FAT_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT #define CONFIG_SPL_LIBCOMMON_SUPPORT #define CONFIG_SPL_LIBDISK_SUPPORT |