diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/designware_i2c.c | 121 | ||||
| -rw-r--r-- | drivers/i2c/designware_i2c.h | 9 | ||||
| -rw-r--r-- | drivers/i2c/mxc_i2c.c | 4 | ||||
| -rw-r--r-- | drivers/i2c/mxs_i2c.c | 80 | ||||
| -rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 15 | ||||
| -rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 19 | ||||
| -rw-r--r-- | drivers/i2c/soft_i2c.c | 3 | 
7 files changed, 191 insertions, 60 deletions
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index bf64a2a64..665387091 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -26,7 +26,12 @@  #include <asm/arch/hardware.h>  #include "designware_i2c.h" -static struct i2c_regs *const i2c_regs_p = +#ifdef CONFIG_I2C_MULTI_BUS +static unsigned int bus_initialized[CONFIG_SYS_I2C_BUS_MAX]; +static unsigned int current_bus = 0; +#endif + +static struct i2c_regs *i2c_regs_p =      (struct i2c_regs *)CONFIG_SYS_I2C_BASE;  /* @@ -39,7 +44,6 @@ static void set_speed(int i2c_spd)  {  	unsigned int cntl;  	unsigned int hcnt, lcnt; -	unsigned int high, low;  	unsigned int enbl;  	/* to set speed cltr must be disabled */ @@ -47,39 +51,38 @@ static void set_speed(int i2c_spd)  	enbl &= ~IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable); -  	cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK));  	switch (i2c_spd) {  	case IC_SPEED_MODE_MAX:  		cntl |= IC_CON_SPD_HS; -		high = MIN_HS_SCL_HIGHTIME; -		low = MIN_HS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_hs_scl_hcnt); +		lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_hs_scl_lcnt);  		break;  	case IC_SPEED_MODE_STANDARD:  		cntl |= IC_CON_SPD_SS; -		high = MIN_SS_SCL_HIGHTIME; -		low = MIN_SS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_ss_scl_hcnt); +		lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_ss_scl_lcnt);  		break;  	case IC_SPEED_MODE_FAST:  	default:  		cntl |= IC_CON_SPD_FS; -		high = MIN_FS_SCL_HIGHTIME; -		low = MIN_FS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); +		lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt);  		break;  	}  	writel(cntl, &i2c_regs_p->ic_con); -	hcnt = (IC_CLK * high) / NANO_TO_MICRO; -	writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); - -	lcnt = (IC_CLK * low) / NANO_TO_MICRO; -	writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); - -	/* re-enable i2c ctrl back now that speed is set */ +	/* Enable back i2c now speed set */  	enbl |= IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable);  } @@ -150,6 +153,10 @@ void i2c_init(int speed, int slaveadd)  	enbl = readl(&i2c_regs_p->ic_enable);  	enbl |= IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable); + +#ifdef CONFIG_I2C_MULTI_BUS +	bus_initialized[current_bus] = 1; +#endif  }  /* @@ -274,7 +281,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)  	start_time_rx = get_timer(0);  	while (len) { -		writel(IC_CMD, &i2c_regs_p->ic_cmd_data); +		if (len == 1) +			writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data); +		else +			writel(IC_CMD, &i2c_regs_p->ic_cmd_data);  		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) {  			*buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); @@ -313,9 +323,11 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  	start_time_tx = get_timer(0);  	while (len) {  		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { -			writel(*buffer, &i2c_regs_p->ic_cmd_data); +			if (--len == 0) +				writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data); +			else +				writel(*buffer, &i2c_regs_p->ic_cmd_data);  			buffer++; -			len--;  			start_time_tx = get_timer(0);  		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { @@ -344,3 +356,74 @@ int i2c_probe(uchar chip)  	return ret;  } + +#ifdef CONFIG_I2C_MULTI_BUS +int i2c_set_bus_num(unsigned int bus) +{ +	switch (bus) { +	case 0: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE; +		break; +#ifdef CONFIG_SYS_I2C_BASE1 +	case 1: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE1; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE2 +	case 2: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE2; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE3 +	case 3: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE3; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE4 +	case 4: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE4; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE5 +	case 5: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE5; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE6 +	case 6: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE6; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE7 +	case 7: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE7; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE8 +	case 8: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE8; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE9 +	case 9: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE9; +		break; +#endif +	default: +		printf("Bad bus: %d\n", bus); +		return -1; +	} + +	current_bus = bus; + +	if (!bus_initialized[current_bus]) +		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + +	return 0; +} + +int i2c_get_bus_num(void) +{ +	return current_bus; +} +#endif diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h index 03b520ed4..2faf4a871 100644 --- a/drivers/i2c/designware_i2c.h +++ b/drivers/i2c/designware_i2c.h @@ -60,14 +60,16 @@ struct i2c_regs {  	u32 ic_tx_abrt_source;  }; +#if !defined(IC_CLK)  #define IC_CLK			166 +#endif  #define NANO_TO_MICRO		1000  /* High and low times in different speed modes (in ns) */  #define MIN_SS_SCL_HIGHTIME	4000 -#define MIN_SS_SCL_LOWTIME	5000 -#define MIN_FS_SCL_HIGHTIME	800 -#define MIN_FS_SCL_LOWTIME	1700 +#define MIN_SS_SCL_LOWTIME	4700 +#define MIN_FS_SCL_HIGHTIME	600 +#define MIN_FS_SCL_LOWTIME	1300  #define MIN_HS_SCL_HIGHTIME	60  #define MIN_HS_SCL_LOWTIME	160 @@ -95,6 +97,7 @@ struct i2c_regs {  /* i2c data buffer and command register definitions */  #define IC_CMD			0x0100 +#define IC_STOP			0x0200  /* i2c interrupt status register definitions */  #define IC_GEN_CALL		0x0800 diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 18270b9de..a73b10b9c 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -115,7 +115,7 @@ static uint8_t i2c_imx_get_clk(unsigned int rate)  /*   * Set I2C Bus speed   */ -int bus_i2c_set_bus_speed(void *base, int speed) +static int bus_i2c_set_bus_speed(void *base, int speed)  {  	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;  	u8 clk_idx = i2c_imx_get_clk(speed); @@ -133,7 +133,7 @@ int bus_i2c_set_bus_speed(void *base, int speed)  /*   * Get I2C Speed   */ -unsigned int bus_i2c_get_bus_speed(void *base) +static unsigned int bus_i2c_get_bus_speed(void *base)  {  	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;  	u8 clk_idx = readb(&i2c_regs->ifdr); diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index 2a193c220..b907f7b37 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -28,6 +28,7 @@  #include <common.h>  #include <malloc.h> +#include <i2c.h>  #include <asm/errno.h>  #include <asm/io.h>  #include <asm/arch/clock.h> @@ -40,6 +41,7 @@ void mxs_i2c_reset(void)  {  	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;  	int ret; +	int speed = i2c_get_bus_speed();  	ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);  	if (ret) { @@ -53,6 +55,8 @@ void mxs_i2c_reset(void)  		&i2c_regs->hw_i2c_ctrl1_clr);  	writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set); + +	i2c_set_bus_speed(speed);  }  void mxs_i2c_setup_read(uint8_t chip, int len) @@ -210,37 +214,65 @@ int i2c_probe(uchar chip)  	return ret;  } -void i2c_init(int speed, int slaveadd) +int i2c_set_bus_speed(unsigned int speed)  {  	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; +	/* +	 * The timing derivation algorithm. There is no documentation for this +	 * algorithm available, it was derived by using the scope and fiddling +	 * with constants until the result observed on the scope was good enough +	 * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be +	 * possible to assume the algorithm works for other frequencies as well. +	 * +	 * Note it was necessary to cap the frequency on both ends as it's not +	 * possible to configure completely arbitrary frequency for the I2C bus +	 * clock. +	 */ +	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); +	uint32_t base = ((clk / speed) - 38) / 2; +	uint16_t high_count = base + 3; +	uint16_t low_count = base - 3; +	uint16_t rcv_count = (high_count * 3) / 4; +	uint16_t xmit_count = low_count / 4; -	mxs_i2c_reset(); +	if (speed > 540000) { +		printf("MXS I2C: Speed too high (%d Hz)\n", speed); +		return -EINVAL; +	} -	switch (speed) { -	case 100000: -		writel((0x0078 << I2C_TIMING0_HIGH_COUNT_OFFSET) | -			(0x0030 << I2C_TIMING0_RCV_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing0); -		writel((0x0080 << I2C_TIMING1_LOW_COUNT_OFFSET) | -			(0x0030 << I2C_TIMING1_XMIT_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing1); -		break; -	case 400000: -		writel((0x000f << I2C_TIMING0_HIGH_COUNT_OFFSET) | -			(0x0007 << I2C_TIMING0_RCV_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing0); -		writel((0x001f << I2C_TIMING1_LOW_COUNT_OFFSET) | -			(0x000f << I2C_TIMING1_XMIT_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing1); -		break; -	default: -		printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed); -		return; +	if (speed < 12000) { +		printf("MXS I2C: Speed too low (%d Hz)\n", speed); +		return -EINVAL;  	} -	writel((0x0015 << I2C_TIMING2_BUS_FREE_OFFSET) | -		(0x000d << I2C_TIMING2_LEADIN_COUNT_OFFSET), +	writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0); +	writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1); + +	writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) | +		(0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET),  		&i2c_regs->hw_i2c_timing2); +	return 0; +} + +unsigned int i2c_get_bus_speed(void) +{ +	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; +	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); +	uint32_t timing0; + +	timing0 = readl(&i2c_regs->hw_i2c_timing0); +	/* +	 * This is a reverse version of the algorithm presented in +	 * i2c_set_bus_speed(). Please refer there for details. +	 */ +	return clk / ((((timing0 >> 16) - 3) * 2) + 38); +} + +void i2c_init(int speed, int slaveadd) +{ +	mxs_i2c_reset(); +	i2c_set_bus_speed(speed); +  	return;  } diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 094305fdf..af454f901 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -179,7 +179,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)  		if (status & I2C_STAT_XRDY) {  			w = tmpbuf[i++];  #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX))  			w |= tmpbuf[i++] << 8;  #endif  			writew(w, &i2c_base->data); @@ -209,7 +210,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)  		}  		if (status & I2C_STAT_RRDY) {  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			*value = readb(&i2c_base->data);  #else  			*value = readw(&i2c_base->data); @@ -239,7 +241,8 @@ 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_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			readb(&i2c_base->data);  #else  			readw(&i2c_base->data); @@ -289,7 +292,8 @@ int i2c_probe(uchar chip)  		if (status & I2C_STAT_RRDY) {  			res = 0;  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -    defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			readb(&i2c_base->data);  #else  			readw(&i2c_base->data); @@ -376,7 +380,8 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  		if (status & I2C_STAT_XRDY) {  			w = (i < 0) ? tmpbuf[2+i] : buffer[i];  #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX))  			w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;  #endif  			writew(w, &i2c_base->data); diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f1d..90d297a28 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,7 +27,7 @@   */  #include <common.h> -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  #include <asm/arch/clk.h>  #include <asm/arch/cpu.h>  #else @@ -62,7 +62,7 @@  static unsigned int g_current_bus;	/* Stores Current I2C Bus */ -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  static int GetI2CSDA(void)  {  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -121,7 +121,12 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c)  static struct s3c24x0_i2c *get_base_i2c(void)  { -#ifdef CONFIG_EXYNOS5 +#ifdef CONFIG_EXYNOS4 +	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() +							+ (EXYNOS4_I2C_SPACING +							* g_current_bus)); +	return i2c; +#elif defined CONFIG_EXYNOS5  	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()  							+ (EXYNOS5_I2C_SPACING  							* g_current_bus)); @@ -134,7 +139,7 @@ static struct s3c24x0_i2c *get_base_i2c(void)  static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)  {  	ulong freq, pres = 16, div; -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	freq = get_i2c_clk();  #else  	freq = get_PCLK(); @@ -188,7 +193,7 @@ unsigned int i2c_get_bus_num(void)  void i2c_init(int speed, int slaveadd)  {  	struct s3c24x0_i2c *i2c; -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();  #endif  	int i; @@ -204,7 +209,7 @@ void i2c_init(int speed, int slaveadd)  		i--;  	} -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {  #ifdef CONFIG_S3C2410  		ulong old_gpecon = readl(&gpio->gpecon); @@ -248,7 +253,7 @@ void i2c_init(int speed, int slaveadd)  		writel(old_gpecon, &gpio->pgcon);  #endif  	} -#endif /* #ifndef CONFIG_EXYNOS5 */ +#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */  	i2c_ch_init(i2c, speed, slaveadd);  } diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 1595c0714..ae3c57392 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -30,6 +30,9 @@  #include <ioports.h>  #include <asm/io.h>  #endif +#if defined(CONFIG_AVR32) +#include <asm/arch/portmux.h> +#endif  #if defined(CONFIG_AT91FAMILY)  #include <asm/io.h>  #include <asm/arch/hardware.h>  |