diff options
| author | Rajeshwari Shinde <rajeshwari.s@samsung.com> | 2012-07-23 21:23:53 +0000 | 
|---|---|---|
| committer | Heiko Schocher <hs@denx.de> | 2012-07-31 08:02:51 +0200 | 
| commit | ab7e52bb240c15ad4426cad64396589beadc9f04 (patch) | |
| tree | e6454bf3c6c487efa406a90507eca90e53bee71a | |
| parent | 91dffb16ffd047458982f70f5cb18c864473a462 (diff) | |
| download | olio-uboot-2014.01-ab7e52bb240c15ad4426cad64396589beadc9f04.tar.xz olio-uboot-2014.01-ab7e52bb240c15ad4426cad64396589beadc9f04.zip | |
I2C: Modify the I2C driver for EXYNOS5
This patch modifies the S3C I2C driver to suppport EXYNOS5.
The cahnges made to driver are as follows:
        - I2C base address is passed as a parameter to many
        functions to avoid multiple #ifdef
        - Channel initialisation is moved to a commom funation
        as it is required by i2c_init.
        - Hardcoding for I2CCON_ACKGEN removed.
        - Replaced printf with debug.
        - Checkpatch issues resolved.
        - Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c
        to avoid repeated setting of gpio lines, as it have multi bus support.
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
Acked-by: Simon Glass <sjg@chromium.org>
| -rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 194 | 
1 files changed, 117 insertions, 77 deletions
| diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ba6f39bee..26c075513 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,10 +27,15 @@   */  #include <common.h> +#ifdef CONFIG_EXYNOS5 +#include <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#else  #include <asm/arch/s3c24x0_cpu.h> - +#endif  #include <asm/io.h>  #include <i2c.h> +#include "s3c24x0_i2c.h"  #ifdef CONFIG_HARD_I2C @@ -45,6 +50,7 @@  #define I2CSTAT_BSY	0x20	/* Busy bit */  #define I2CSTAT_NACK	0x01	/* Nack bit */ +#define I2CCON_ACKGEN	0x80	/* Acknowledge generation */  #define I2CCON_IRPND	0x10	/* Interrupt pending bit */  #define I2C_MODE_MT	0xC0	/* Master Transmit Mode */  #define I2C_MODE_MR	0x80	/* Master Receive Mode */ @@ -53,6 +59,10 @@  #define I2C_TIMEOUT 1		/* 1 second */ + +static unsigned int g_current_bus;	/* Stores Current I2C Bus */ + +#ifndef CONFIG_EXYNOS5  static int GetI2CSDA(void)  {  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -77,16 +87,17 @@ static void SetI2CSCL(int x)  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();  #ifdef CONFIG_S3C2410 -	writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat); +	writel((readl(&gpio->gpedat) & ~0x4000) | +					(x & 1) << 14, &gpio->gpedat);  #endif  #ifdef CONFIG_S3C2400  	writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);  #endif  } +#endif -static int WaitForXfer(void) +static int WaitForXfer(struct s3c24x0_i2c *i2c)  { -	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();  	int i;  	i = I2C_TIMEOUT * 10000; @@ -98,35 +109,75 @@ static int WaitForXfer(void)  	return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;  } -static int IsACK(void) +static int IsACK(struct s3c24x0_i2c *i2c)  { -	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); -  	return !(readl(&i2c->iicstat) & I2CSTAT_NACK);  } -static void ReadWriteByte(void) +static void ReadWriteByte(struct s3c24x0_i2c *i2c)  { -	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); -  	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);  } +static struct s3c24x0_i2c *get_base_i2c(void) +{ +#ifdef CONFIG_EXYNOS5 +	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() +							+ (EXYNOS5_I2C_SPACING +							* g_current_bus)); +	return i2c; +#else +	return s3c24x0_get_base_i2c(); +#endif +} + +static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) +{ +	ulong freq, pres = 16, div; +#ifdef CONFIG_EXYNOS5 +	freq = get_i2c_clk(); +#else +	freq = get_PCLK(); +#endif +	/* calculate prescaler and divisor values */ +	if ((freq / pres / (16 + 1)) > speed) +		/* set prescaler to 512 */ +		pres = 512; + +	div = 0; +	while ((freq / pres / (div + 1)) > speed) +		div++; + +	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */ +	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); + +	/* init to SLAVE REVEIVE and set slaveaddr */ +	writel(0, &i2c->iicstat); +	writel(slaveadd, &i2c->iicadd); +	/* program Master Transmit (and implicit STOP) */ +	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); +} +  void i2c_init(int speed, int slaveadd)  { -	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); +	struct s3c24x0_i2c *i2c; +#ifndef CONFIG_EXYNOS5  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); -	ulong freq, pres = 16, div; +#endif  	int i; -	/* wait for some time to give previous transfer a chance to finish */ +	/* By default i2c channel 0 is the current bus */ +	g_current_bus = 0; +	i2c = get_base_i2c(); +	/* wait for some time to give previous transfer a chance to finish */  	i = I2C_TIMEOUT * 1000; -	while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) { +	while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {  		udelay(1000);  		i--;  	} +#ifndef CONFIG_EXYNOS5  	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {  #ifdef CONFIG_S3C2410  		ulong old_gpecon = readl(&gpio->gpecon); @@ -170,27 +221,8 @@ void i2c_init(int speed, int slaveadd)  		writel(old_gpecon, &gpio->pgcon);  #endif  	} - -	/* calculate prescaler and divisor values */ -	freq = get_PCLK(); -	if ((freq / pres / (16 + 1)) > speed) -		/* set prescaler to 512 */ -		pres = 512; - -	div = 0; -	while ((freq / pres / (div + 1)) > speed) -		div++; - -	/* set prescaler, divisor according to freq, also set -	 * ACKGEN, IRQ */ -	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); - -	/* init to SLAVE REVEIVE and set slaveaddr */ -	writel(0, &i2c->iicstat); -	writel(slaveadd, &i2c->iicadd); -	/* program Master Transmit (and implicit STOP) */ -	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - +#endif /* #ifndef CONFIG_EXYNOS5 */ +	i2c_ch_init(i2c, speed, slaveadd);  }  /* @@ -200,19 +232,19 @@ void i2c_init(int speed, int slaveadd)   * by the char, we could make it larger if needed. If it is   * 0 we skip the address write cycle.   */ -static -int i2c_transfer(unsigned char cmd_type, -		 unsigned char chip, -		 unsigned char addr[], -		 unsigned char addr_len, -		 unsigned char data[], unsigned short data_len) +static int i2c_transfer(struct s3c24x0_i2c *i2c, +			unsigned char cmd_type, +			unsigned char chip, +			unsigned char addr[], +			unsigned char addr_len, +			unsigned char data[], +			unsigned short data_len)  { -	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();  	int i, result;  	if (data == 0 || data_len == 0) {  		/*Don't support data transfer of no length or to address 0 */ -		printf("i2c_transfer: bad call\n"); +		debug("i2c_transfer: bad call\n");  		return I2C_NOK;  	} @@ -226,7 +258,7 @@ int i2c_transfer(unsigned char cmd_type,  	if (readl(&i2c->iicstat) & I2CSTAT_BSY)  		return I2C_NOK_TOUT; -	writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon); +	writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);  	result = I2C_OK;  	switch (cmd_type) { @@ -238,16 +270,16 @@ int i2c_transfer(unsigned char cmd_type,  			       &i2c->iicstat);  			i = 0;  			while ((i < addr_len) && (result == I2C_OK)) { -				result = WaitForXfer(); +				result = WaitForXfer(i2c);  				writel(addr[i], &i2c->iicds); -				ReadWriteByte(); +				ReadWriteByte(i2c);  				i++;  			}  			i = 0;  			while ((i < data_len) && (result == I2C_OK)) { -				result = WaitForXfer(); +				result = WaitForXfer(i2c);  				writel(data[i], &i2c->iicds); -				ReadWriteByte(); +				ReadWriteByte(i2c);  				i++;  			}  		} else { @@ -257,19 +289,19 @@ int i2c_transfer(unsigned char cmd_type,  			       &i2c->iicstat);  			i = 0;  			while ((i < data_len) && (result = I2C_OK)) { -				result = WaitForXfer(); +				result = WaitForXfer(i2c);  				writel(data[i], &i2c->iicds); -				ReadWriteByte(); +				ReadWriteByte(i2c);  				i++;  			}  		}  		if (result == I2C_OK) -			result = WaitForXfer(); +			result = WaitForXfer(i2c);  		/* send STOP */  		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); -		ReadWriteByte(); +		ReadWriteByte(i2c);  		break;  	case I2C_READ: @@ -279,13 +311,13 @@ int i2c_transfer(unsigned char cmd_type,  			/* send START */  			writel(readl(&i2c->iicstat) | I2C_START_STOP,  			       &i2c->iicstat); -			result = WaitForXfer(); -			if (IsACK()) { +			result = WaitForXfer(i2c); +			if (IsACK(i2c)) {  				i = 0;  				while ((i < addr_len) && (result == I2C_OK)) {  					writel(addr[i], &i2c->iicds); -					ReadWriteByte(); -					result = WaitForXfer(); +					ReadWriteByte(i2c); +					result = WaitForXfer(i2c);  					i++;  				} @@ -293,16 +325,17 @@ int i2c_transfer(unsigned char cmd_type,  				/* resend START */  				writel(I2C_MODE_MR | I2C_TXRX_ENA |  				       I2C_START_STOP, &i2c->iicstat); -				ReadWriteByte(); -				result = WaitForXfer(); +			ReadWriteByte(i2c); +			result = WaitForXfer(i2c);  				i = 0;  				while ((i < data_len) && (result == I2C_OK)) {  					/* disable ACK for final READ */  					if (i == data_len - 1)  						writel(readl(&i2c->iiccon) -						       & ~0x80, &i2c->iiccon); -					ReadWriteByte(); -					result = WaitForXfer(); +							& ~I2CCON_ACKGEN, +							&i2c->iiccon); +				ReadWriteByte(i2c); +				result = WaitForXfer(i2c);  					data[i] = readl(&i2c->iicds);  					i++;  				} @@ -316,17 +349,18 @@ int i2c_transfer(unsigned char cmd_type,  			/* send START */  			writel(readl(&i2c->iicstat) | I2C_START_STOP,  			       &i2c->iicstat); -			result = WaitForXfer(); +			result = WaitForXfer(i2c); -			if (IsACK()) { +			if (IsACK(i2c)) {  				i = 0;  				while ((i < data_len) && (result == I2C_OK)) {  					/* disable ACK for final READ */  					if (i == data_len - 1)  						writel(readl(&i2c->iiccon) & -						       ~0x80, &i2c->iiccon); -					ReadWriteByte(); -					result = WaitForXfer(); +							~I2CCON_ACKGEN, +							&i2c->iiccon); +					ReadWriteByte(i2c); +					result = WaitForXfer(i2c);  					data[i] = readl(&i2c->iicds);  					i++;  				} @@ -337,22 +371,24 @@ int i2c_transfer(unsigned char cmd_type,  		/* send STOP */  		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); -		ReadWriteByte(); +		ReadWriteByte(i2c);  		break;  	default: -		printf("i2c_transfer: bad call\n"); +		debug("i2c_transfer: bad call\n");  		result = I2C_NOK;  		break;  	} -	return (result); +	return result;  }  int i2c_probe(uchar chip)  { +	struct s3c24x0_i2c *i2c;  	uchar buf[1]; +	i2c = get_base_i2c();  	buf[0] = 0;  	/* @@ -360,16 +396,17 @@ int i2c_probe(uchar chip)  	 * address was <ACK>ed (i.e. there was a chip at that address which  	 * drove the data line low).  	 */ -	return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; +	return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;  }  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)  { +	struct s3c24x0_i2c *i2c;  	uchar xaddr[4];  	int ret;  	if (alen > 4) { -		printf("I2C read: addr len %d not supported\n", alen); +		debug("I2C read: addr len %d not supported\n", alen);  		return 1;  	} @@ -396,10 +433,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)  		chip |= ((addr >> (alen * 8)) &  			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);  #endif -	if ((ret = -	     i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen, -			  buffer, len)) != 0) { -		printf("I2c read: failed %d\n", ret); +	i2c = get_base_i2c(); +	ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, +			buffer, len); +	if (ret != 0) { +		debug("I2c read: failed %d\n", ret);  		return 1;  	}  	return 0; @@ -407,10 +445,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)  int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  { +	struct s3c24x0_i2c *i2c;  	uchar xaddr[4];  	if (alen > 4) { -		printf("I2C write: addr len %d not supported\n", alen); +		debug("I2C write: addr len %d not supported\n", alen);  		return 1;  	} @@ -436,8 +475,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  		chip |= ((addr >> (alen * 8)) &  			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);  #endif +	i2c = get_base_i2c();  	return (i2c_transfer -		(I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, +		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,  		 len) != 0);  }  #endif /* CONFIG_HARD_I2C */ |