diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/bfin-twi_i2c.c | 169 | 
1 files changed, 108 insertions, 61 deletions
| diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c index 73a78d223..b3a04d320 100644 --- a/drivers/i2c/bfin-twi_i2c.c +++ b/drivers/i2c/bfin-twi_i2c.c @@ -1,7 +1,7 @@  /*   * i2c.c - driver for Blackfin on-chip TWI/I2C   * - * Copyright (c) 2006-2008 Analog Devices Inc. + * Copyright (c) 2006-2010 Analog Devices Inc.   *   * Licensed under the GPL-2 or later.   */ @@ -12,6 +12,35 @@  #include <asm/blackfin.h>  #include <asm/mach-common/bits/twi.h> +/* Every register is 32bit aligned, but only 16bits in size */ +#define ureg(name) u16 name; u16 __pad_##name; +struct twi_regs { +	ureg(clkdiv); +	ureg(control); +	ureg(slave_ctl); +	ureg(slave_stat); +	ureg(slave_addr); +	ureg(master_ctl); +	ureg(master_stat); +	ureg(master_addr); +	ureg(int_stat); +	ureg(int_mask); +	ureg(fifo_ctl); +	ureg(fifo_stat); +	char __pad[0x50]; +	ureg(xmt_data8); +	ureg(xmt_data16); +	ureg(rcv_data8); +	ureg(rcv_data16); +}; +#undef ureg + +/* U-Boot I2C framework allows only one active device at a time.  */ +#ifdef TWI_CLKDIV +#define TWI0_CLKDIV TWI_CLKDIV +#endif +static volatile struct twi_regs *twi = (void *)TWI0_CLKDIV; +  #ifdef DEBUG  # define dmemset(s, c, n) memset(s, c, n)  #else @@ -19,29 +48,10 @@  #endif  #define debugi(fmt, args...) \  	debug( \ -		"MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t" \ -		"%-20s:%-3i: " fmt "\n", \ -		bfin_read_TWI_MASTER_STAT(), bfin_read_TWI_FIFO_STAT(), bfin_read_TWI_INT_STAT(), \ +		"MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t%-20s:%-3i: " fmt "\n", \ +		twi->master_stat, twi->fifo_stat, twi->int_stat, \  		__func__, __LINE__, ## args) -#ifdef TWI0_CLKDIV -#define bfin_write_TWI_CLKDIV(val)           bfin_write_TWI0_CLKDIV(val) -#define bfin_read_TWI_CLKDIV(val)            bfin_read_TWI0_CLKDIV(val) -#define bfin_write_TWI_CONTROL(val)          bfin_write_TWI0_CONTROL(val) -#define bfin_read_TWI_CONTROL(val)           bfin_read_TWI0_CONTROL(val) -#define bfin_write_TWI_MASTER_ADDR(val)      bfin_write_TWI0_MASTER_ADDR(val) -#define bfin_write_TWI_XMT_DATA8(val)        bfin_write_TWI0_XMT_DATA8(val) -#define bfin_read_TWI_RCV_DATA8()            bfin_read_TWI0_RCV_DATA8() -#define bfin_read_TWI_INT_STAT()             bfin_read_TWI0_INT_STAT() -#define bfin_write_TWI_INT_STAT(val)         bfin_write_TWI0_INT_STAT(val) -#define bfin_read_TWI_MASTER_STAT()          bfin_read_TWI0_MASTER_STAT() -#define bfin_write_TWI_MASTER_STAT(val)      bfin_write_TWI0_MASTER_STAT(val) -#define bfin_read_TWI_MASTER_CTL()           bfin_read_TWI0_MASTER_CTL() -#define bfin_write_TWI_MASTER_CTL(val)       bfin_write_TWI0_MASTER_CTL(val) -#define bfin_write_TWI_INT_MASK(val)         bfin_write_TWI0_INT_MASK(val) -#define bfin_write_TWI_FIFO_CTL(val)         bfin_write_TWI0_FIFO_CTL(val) -#endif -  #ifdef CONFIG_TWICLK_KHZ  # error do not define CONFIG_TWICLK_KHZ ... use CONFIG_SYS_I2C_SPEED  #endif @@ -87,49 +97,48 @@ static int wait_for_completion(struct i2c_msg *msg)  	ulong timebase = get_timer(0);  	do { -		int_stat = bfin_read_TWI_INT_STAT(); +		int_stat = twi->int_stat;  		if (int_stat & XMTSERV) {  			debugi("processing XMTSERV"); -			bfin_write_TWI_INT_STAT(XMTSERV); +			twi->int_stat = XMTSERV;  			SSYNC();  			if (msg->alen) { -				bfin_write_TWI_XMT_DATA8(*(msg->abuf++)); +				twi->xmt_data8 = *(msg->abuf++);  				--msg->alen;  			} else if (!(msg->flags & I2C_M_COMBO) && msg->len) { -				bfin_write_TWI_XMT_DATA8(*(msg->buf++)); +				twi->xmt_data8 = *(msg->buf++);  				--msg->len;  			} else { -				bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | -					(msg->flags & I2C_M_COMBO ? RSTART | MDIR : STOP)); +				twi->master_ctl |= (msg->flags & I2C_M_COMBO) ? RSTART | MDIR : STOP;  				SSYNC();  			}  		}  		if (int_stat & RCVSERV) {  			debugi("processing RCVSERV"); -			bfin_write_TWI_INT_STAT(RCVSERV); +			twi->int_stat = RCVSERV;  			SSYNC();  			if (msg->len) { -				*(msg->buf++) = bfin_read_TWI_RCV_DATA8(); +				*(msg->buf++) = twi->rcv_data8;  				--msg->len;  			} else if (msg->flags & I2C_M_STOP) { -				bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | STOP); +				twi->master_ctl |= STOP;  				SSYNC();  			}  		}  		if (int_stat & MERR) {  			debugi("processing MERR"); -			bfin_write_TWI_INT_STAT(MERR); +			twi->int_stat = MERR;  			SSYNC();  			return msg->len;  		}  		if (int_stat & MCOMP) {  			debugi("processing MCOMP"); -			bfin_write_TWI_INT_STAT(MCOMP); +			twi->int_stat = MCOMP;  			SSYNC();  			if (msg->flags & I2C_M_COMBO && msg->len) { -				bfin_write_TWI_MASTER_CTL((bfin_read_TWI_MASTER_CTL() & ~RSTART) | -					(min(msg->len, 0xff) << 6) | MEN | MDIR); +				twi->master_ctl = (twi->master_ctl & ~RSTART) | +					(min(msg->len, 0xff) << 6) | MEN | MDIR;  				SSYNC();  			} else  				break; @@ -172,55 +181,54 @@ static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len,  		chip, addr, alen, buffer[0], len, flags, (flags & I2C_M_READ ? "rd" : "wr"));  	/* wait for things to settle */ -	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) +	while (twi->master_stat & BUSBUSY)  		if (ctrlc())  			return 1;  	/* Set Transmit device address */ -	bfin_write_TWI_MASTER_ADDR(chip); +	twi->master_addr = chip;  	/* Clear the FIFO before starting things */ -	bfin_write_TWI_FIFO_CTL(XMTFLUSH | RCVFLUSH); +	twi->fifo_ctl = XMTFLUSH | RCVFLUSH;  	SSYNC(); -	bfin_write_TWI_FIFO_CTL(0); +	twi->fifo_ctl = 0;  	SSYNC();  	/* prime the pump */  	if (msg.alen) {  		len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len;  		debugi("first byte=0x%02x", *msg.abuf); -		bfin_write_TWI_XMT_DATA8(*(msg.abuf++)); +		twi->xmt_data8 = *(msg.abuf++);  		--msg.alen;  	} else if (!(msg.flags & I2C_M_READ) && msg.len) {  		debugi("first byte=0x%02x", *msg.buf); -		bfin_write_TWI_XMT_DATA8(*(msg.buf++)); +		twi->xmt_data8 = *(msg.buf++);  		--msg.len;  	}  	/* clear int stat */ -	bfin_write_TWI_MASTER_STAT(-1); -	bfin_write_TWI_INT_STAT(-1); -	bfin_write_TWI_INT_MASK(0); +	twi->master_stat = -1; +	twi->int_stat = -1; +	twi->int_mask = 0;  	SSYNC();  	/* Master enable */ -	bfin_write_TWI_MASTER_CTL( -			(bfin_read_TWI_MASTER_CTL() & FAST) | +	twi->master_ctl = +			(twi->master_ctl & FAST) |  			(min(len, 0xff) << 6) | MEN | -			((msg.flags & I2C_M_READ) ? MDIR : 0) -	); +			((msg.flags & I2C_M_READ) ? MDIR : 0);  	SSYNC(); -	debugi("CTL=0x%04x", bfin_read_TWI_MASTER_CTL()); +	debugi("CTL=0x%04x", twi->master_ctl);  	/* process the rest */  	ret = wait_for_completion(&msg);  	debugi("ret=%d", ret);  	if (ret) { -		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & ~MEN); -		bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA); +		twi->master_ctl &= ~MEN; +		twi->control &= ~TWI_ENA;  		SSYNC(); -		bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); +		twi->control |= TWI_ENA;  		SSYNC();  	} @@ -238,10 +246,10 @@ int i2c_set_bus_speed(unsigned int speed)  	/* Set TWI interface clock */  	if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)  		return -1; -	bfin_write_TWI_CLKDIV((clkdiv << 8) | (clkdiv & 0xff)); +	twi->clkdiv = (clkdiv << 8) | (clkdiv & 0xff);  	/* Don't turn it on */ -	bfin_write_TWI_MASTER_CTL(speed > 100000 ? FAST : 0); +	twi->master_ctl = (speed > 100000 ? FAST : 0);  	return 0;  } @@ -253,7 +261,7 @@ int i2c_set_bus_speed(unsigned int speed)  unsigned int i2c_get_bus_speed(void)  {  	/* 10 MHz / (2 * CLKDIV) -> 5 MHz / CLKDIV */ -	return 5000000 / (bfin_read_TWI_CLKDIV() & 0xff); +	return 5000000 / (twi->clkdiv & 0xff);  }  /** @@ -269,24 +277,23 @@ void i2c_init(int speed, int slaveaddr)  	uint8_t prescale = ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F;  	/* Set TWI internal clock as 10MHz */ -	bfin_write_TWI_CONTROL(prescale); +	twi->control = prescale;  	/* Set TWI interface clock as specified */  	i2c_set_bus_speed(speed);  	/* Enable it */ -	bfin_write_TWI_CONTROL(TWI_ENA | prescale); +	twi->control = TWI_ENA | prescale;  	SSYNC(); -	debugi("CONTROL:0x%04x CLKDIV:0x%04x", -		bfin_read_TWI_CONTROL(), bfin_read_TWI_CLKDIV()); +	debugi("CONTROL:0x%04x CLKDIV:0x%04x", twi->control, twi->clkdiv);  #if CONFIG_SYS_I2C_SLAVE  # error I2C slave support not tested/supported  	/* If they want us as a slave, do it */  	if (slaveaddr) { -		bfin_write_TWI_SLAVE_ADDR(slaveaddr); -		bfin_write_TWI_SLAVE_CTL(SEN); +		twi->slave_addr = slaveaddr; +		twi->slave_ctl = SEN;  	}  #endif  } @@ -329,3 +336,43 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  {  	return i2c_transfer(chip, addr, alen, buffer, len, 0);  } + +/** + * i2c_set_bus_num - change active I2C bus + *	@bus: bus index, zero based + *	@returns: 0 on success, non-0 on failure + */ +int i2c_set_bus_num(unsigned int bus) +{ +	switch (bus) { +#if CONFIG_SYS_MAX_I2C_BUS > 0 +		case 0: twi = (void *)TWI0_CLKDIV; return 0; +#endif +#if CONFIG_SYS_MAX_I2C_BUS > 1 +		case 1: twi = (void *)TWI1_CLKDIV; return 0; +#endif +#if CONFIG_SYS_MAX_I2C_BUS > 2 +		case 2: twi = (void *)TWI2_CLKDIV; return 0; +#endif +		default: return -1; +	} +} + +/** + * i2c_get_bus_num - returns index of active I2C bus + */ +unsigned int i2c_get_bus_num(void) +{ +	switch ((unsigned long)twi) { +#if CONFIG_SYS_MAX_I2C_BUS > 0 +		case TWI0_CLKDIV: return 0; +#endif +#if CONFIG_SYS_MAX_I2C_BUS > 1 +		case TWI1_CLKDIV: return 1; +#endif +#if CONFIG_SYS_MAX_I2C_BUS > 2 +		case TWI2_CLKDIV: return 2; +#endif +		default: return -1; +	} +} |