diff options
| author | Wolfgang Denk <wd@denx.de> | 2010-10-20 21:23:22 +0200 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2010-10-20 21:23:22 +0200 | 
| commit | b76335178ed399d5843be6bf97707cc9d1b16bbd (patch) | |
| tree | 21ee72b7c51b1090638297b64a835c91fb6eb263 /drivers/i2c/omap24xx_i2c.c | |
| parent | d9d47d18e8cee8ae290218ce5d9669b9563073e3 (diff) | |
| parent | fbad3555624a738a632ddb1b968e98a20e743941 (diff) | |
| download | olio-uboot-2014.01-b76335178ed399d5843be6bf97707cc9d1b16bbd.tar.xz olio-uboot-2014.01-b76335178ed399d5843be6bf97707cc9d1b16bbd.zip | |
Merge branch 'master' of git://git.denx.de/u-boot-i2c
Diffstat (limited to 'drivers/i2c/omap24xx_i2c.c')
| -rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 207 | 
1 files changed, 116 insertions, 91 deletions
| diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 3febd1ff6..a72d1a125 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -27,7 +27,7 @@  #include "omap24xx_i2c.h" -#define I2C_TIMEOUT	10 +#define I2C_TIMEOUT	1000  static void wait_for_bb (void);  static u16 wait_for_pin (void); @@ -159,58 +159,56 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)  	/* no stop bit needed here */  	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_base->data); -		udelay (20000); -		if (readw (&i2c_base->stat) & I2C_STAT_NACK) { +	/* send register offset */ +	while (1) { +		status = wait_for_pin(); +		if (status == 0 || status & I2C_STAT_NACK) {  			i2c_error = 1; +			goto read_exit;  		} -	} else { -		i2c_error = 1; -	} - -	if (!i2c_error) { -		writew (I2C_CON_EN, &i2c_base->con); -		while (readw(&i2c_base->stat) & -			(I2C_STAT_XRDY | I2C_STAT_ARDY)) { -			udelay (10000); -			/* Have to clear pending interrupt to clear I2C_STAT */ -			writew (0xFFFF, &i2c_base->stat); +		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); +	/* 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); -		status = wait_for_pin (); +	/* 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); +			*value = readb(&i2c_base->data);  #else -			*value = readw (&i2c_base->data); +			*value = readw(&i2c_base->data);  #endif -			udelay (20000); -		} else { -			i2c_error = 1; +			writew(I2C_STAT_RRDY, &i2c_base->stat);  		} - -		if (!i2c_error) { -			writew (I2C_CON_EN, &i2c_base->con); -			while (readw (&i2c_base->stat) & -				(I2C_STAT_RRDY | I2C_STAT_ARDY)) { -				udelay (10000); -				writew (0xFFFF, &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); @@ -220,7 +218,7 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)  static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)  {  	int i2c_error = 0; -	u16 status, stat; +	u16 status;  	/* wait until bus not busy */  	wait_for_bb (); @@ -233,49 +231,55 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)  	writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |  		I2C_CON_STP, &i2c_base->con); -	/* wait until state change */ -	status = wait_for_pin (); - -	if (status & I2C_STAT_XRDY) { +	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 out 1 byte */ -		writeb (regoffset, &i2c_base->data); -		writew (I2C_STAT_XRDY, &i2c_base->stat); +			/* send register offset */ +			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_base->data); -			writew (I2C_STAT_XRDY, &i2c_base->stat); -		} else { -			i2c_error = 1; -		} +			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); +			/* send out two bytes */ +			writew((value << 8) + regoffset, &i2c_base->data); +			writew(I2C_STAT_XRDY, &i2c_base->stat);  #endif -		/* must have enough delay to allow BB bit to go low */ -		udelay (50000); -		if (readw (&i2c_base->stat) & I2C_STAT_NACK) { -			i2c_error = 1;  		} -	} else { -		i2c_error = 1; +		if (status & I2C_STAT_ARDY) { +			writew(I2C_STAT_ARDY, &i2c_base->stat); +			break; +		}  	} -	if (!i2c_error) { -		int eout = 200; +	wait_for_bb(); -		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_base->stat); -			if(--eout == 0) /* better leave with error than hang */ -				break; -		} -	} +	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); @@ -306,6 +310,7 @@ static void flush_fifo(void)  int i2c_probe (uchar chip)  { +	u16 status;  	int res = 1; /* default = fail */  	if (chip == readw (&i2c_base->oa)) { @@ -321,19 +326,37 @@ int i2c_probe (uchar chip)  	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); -	/* enough delay for the NACK bit set */ -	udelay (50000); -	if (!(readw (&i2c_base->stat) & I2C_STAT_NACK)) { -		res = 0;      /* success case */ -		flush_fifo(); -		writew(0xFFFF, &i2c_base->stat); -	} else { -		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 (); +	while (1) { +		status = wait_for_pin(); +		if (status == 0) { +			res = 1; +			goto probe_exit; +		} +		if (status & I2C_STAT_NACK) { +			res = 1; +			writew(0xff, &i2c_base->stat); +			writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); +			wait_for_bb (); +			break; +		} +		if (status & I2C_STAT_ARDY) { +			writew(I2C_STAT_ARDY, &i2c_base->stat); +			break; +		} +		if (status & I2C_STAT_RRDY) { +			res = 0; +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ +    defined(CONFIG_OMAP44XX) +			readb(&i2c_base->data); +#else +			readw(&i2c_base->data); +#endif +			writew(I2C_STAT_RRDY, &i2c_base->stat); +		}  	} + +probe_exit:  	flush_fifo();  	writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/  	writew(0xFFFF, &i2c_base->stat); @@ -392,13 +415,13 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)  static void wait_for_bb (void)  { -	int timeout = 10; +	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); -		udelay (50000); +		udelay(1000);  	}  	if (timeout <= 0) { @@ -411,7 +434,7 @@ static void wait_for_bb (void)  static u16 wait_for_pin (void)  {  	u16 status; -	int timeout = 10; +	int timeout = I2C_TIMEOUT;  	do {  		udelay (1000); @@ -424,8 +447,10 @@ static u16 wait_for_pin (void)  	if (timeout <= 0) {  		printf ("timed out in wait_for_pin: I2C_STAT=%x\n",  			readw (&i2c_base->stat)); -			writew(0xFFFF, &i2c_base->stat); -} +		writew(0xFFFF, &i2c_base->stat); +		status = 0; +	} +  	return status;  } |