|  |  |  | @ -1,5 +1,6 @@ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #include "i2c.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "interrupt.h" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define I2CBASE  0xE001C000 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -21,6 +22,11 @@ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define SI (IREG(I2CONSET) & SIFLAG) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void __attribute__((interrupt("IRQ"))) i2c_interrupt_handler(void); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | struct i2c_transaction *i2c_transaction; | 
			
		
	
		
			
				
					|  |  |  |  | int i2c_bytes; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void init_i2c(void) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONSET) = 0x40; /* Enable I2C ready for Master Tx */ | 
			
		
	
	
		
			
				
					|  |  |  | @ -32,17 +38,7 @@ void init_i2c(void) | 
			
		
	
		
			
				
					|  |  |  |  | 	IWREG(I2SCLL) = 73; /* ~100kHz */ | 
			
		
	
		
			
				
					|  |  |  |  | 	IWREG(I2SCLH) = 73; | 
			
		
	
		
			
				
					|  |  |  |  | #endif | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | int i2cstat; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | int i2c_wait(void) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	int stat; | 
			
		
	
		
			
				
					|  |  |  |  | 	while (!SI); | 
			
		
	
		
			
				
					|  |  |  |  | 	stat = IREG(I2STAT); | 
			
		
	
		
			
				
					|  |  |  |  | 	i2cstat = stat; | 
			
		
	
		
			
				
					|  |  |  |  | 	return stat; | 
			
		
	
		
			
				
					|  |  |  |  | 	interrupt_register(I2C0, i2c_interrupt_handler); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | int i2c_conreg(void) | 
			
		
	
	
		
			
				
					|  |  |  | @ -55,61 +51,110 @@ int i2c_statreg(void) | 
			
		
	
		
			
				
					|  |  |  |  | 	return IREG(I2STAT); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_send_start(void) | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_busy(void) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = STOFLAG | STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONSET) = STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	switch (i2c_wait()) { | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x08: | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x10: | 
			
		
	
		
			
				
					|  |  |  |  | 		return TRUE; | 
			
		
	
		
			
				
					|  |  |  |  | 	default: | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_send_stop(); | 
			
		
	
		
			
				
					|  |  |  |  | 		return FALSE; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	return i2c_transaction != NULL; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_send_address(int addr, bool write) | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_start_transaction(struct i2c_transaction *t) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	return i2c_send_data((addr<<1) + (write?0:1)); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (i2c_transaction) | 
			
		
	
		
			
				
					|  |  |  |  | 		return FALSE; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	i2c_transaction = t; | 
			
		
	
		
			
				
					|  |  |  |  | 	*(t->result) = I2C_IN_PROGRESS; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/* Paranoia in case we left things in a bad state */ | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = STOFLAG | STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/* Set it all going */ | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONSET) = STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return TRUE; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_send_data(unsigned int data) | 
			
		
	
		
			
				
					|  |  |  |  | void __attribute__((interrupt("IRQ"))) i2c_interrupt_handler(void) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2DAT) = data; | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	switch (i2c_wait()) { | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x18: | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x28: | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x40: | 
			
		
	
		
			
				
					|  |  |  |  | 		return TRUE; | 
			
		
	
		
			
				
					|  |  |  |  | 	default: | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_send_stop(); | 
			
		
	
		
			
				
					|  |  |  |  | 		return FALSE; | 
			
		
	
		
			
				
					|  |  |  |  | 	int stat = IREG(I2STAT); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!i2c_transaction) { | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONSET) = STOFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		interrupt_clear(); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | bool i2c_receive_data(unsigned int *data, bool last) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!last) | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONSET) = AAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG | (last?AAFLAG:0); | 
			
		
	
		
			
				
					|  |  |  |  | 	switch (i2c_wait()) { | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x50: | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x58: | 
			
		
	
		
			
				
					|  |  |  |  | 		*data = IREG(I2DAT); | 
			
		
	
		
			
				
					|  |  |  |  | 		return TRUE; | 
			
		
	
		
			
				
					|  |  |  |  | 	default: | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_send_stop(); | 
			
		
	
		
			
				
					|  |  |  |  | 		return FALSE; | 
			
		
	
		
			
				
					|  |  |  |  | 	switch (stat) { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x08: /* START transmitted */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x10: /* repeated START transmitted */ | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2DAT) = i2c_transaction->address; | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_bytes = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		break; | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x18: /* SA+W transmitted, ACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x28: /* data transmitted, ACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 		if (i2c_bytes < i2c_transaction->bytes) { | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2DAT) = i2c_transaction->data[i2c_bytes++]; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			*(i2c_transaction->result) = I2C_SUCCESS; | 
			
		
	
		
			
				
					|  |  |  |  | 			if (i2c_transaction->next) { | 
			
		
	
		
			
				
					|  |  |  |  | 				i2c_transaction = i2c_transaction->next; | 
			
		
	
		
			
				
					|  |  |  |  | 				i2c_bytes = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 				IREG(I2CONSET) = STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 				IREG(I2CONCLR) = STOFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				i2c_transaction = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 				IREG(I2CONSET) = STOFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 				IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x50: /* data received, ACK returned */ | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_transaction->data[i2c_bytes++] = IREG(I2DAT); | 
			
		
	
		
			
				
					|  |  |  |  | 		/* fall through */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x40: /* SA+R transmitted, ACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 		if (i2c_bytes < (i2c_transaction->bytes-1)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONSET) = AAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG 
 | 
			
		
	
		
			
				
					|  |  |  |  | 							   | AAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x58: /* data received, NACK returned */ | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_transaction->data[i2c_bytes] = IREG(I2DAT); | 
			
		
	
		
			
				
					|  |  |  |  | 		*(i2c_transaction->result) = I2C_SUCCESS; | 
			
		
	
		
			
				
					|  |  |  |  | 		if (i2c_transaction->next) { | 
			
		
	
		
			
				
					|  |  |  |  | 			i2c_transaction = i2c_transaction->next; | 
			
		
	
		
			
				
					|  |  |  |  | 			i2c_bytes = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONSET) = STAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONCLR) = STOFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			i2c_transaction = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONSET) = STOFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 			IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x20: /* SA+W transmitted, NACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x30: /* data transmitted, NACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x48: /* SA+R transmitted, NACK received */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x38: /* arbitration lost during SA+W or data */ | 
			
		
	
		
			
				
					|  |  |  |  | 	case 0x00: /* bus error */ | 
			
		
	
		
			
				
					|  |  |  |  | 		*(i2c_transaction->result) = I2C_FAIL; | 
			
		
	
		
			
				
					|  |  |  |  | 		i2c_transaction = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONSET) = STOFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 		break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/* We don't handle slave mode */ | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void i2c_send_stop(void) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = STAFLAG | AAFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONSET) = STOFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	IREG(I2CONCLR) = SIFLAG; | 
			
		
	
		
			
				
					|  |  |  |  | 	/* Don't think we need to wait here. Could be wrong. */ | 
			
		
	
		
			
				
					|  |  |  |  | 	interrupt_clear(); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |