⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 U-boot源码 ARM7启动代码
💻 C
字号:
/**************************************************************** * $ID: i2c.c	24 Oct 2006 12:00:00 +0800 $ 			* *								* * Description:							* *								* * Maintainer:  sonicz  <sonic.zhang@analog.com>		* *								* * CopyRight (c)  2006  Analog Device				* * All rights reserved.						* *								* * This file is free software;					* *	you are free to modify and/or redistribute it		* *	under the terms of the GNU General Public Licence (GPL).* *								* ****************************************************************/#include <common.h>#ifdef CONFIG_HARD_I2C#include <asm/blackfin.h>#include <i2c.h>#include <asm/io.h>DECLARE_GLOBAL_DATA_PTR;#define bfin_read16(addr) ({ unsigned __v; \			__asm__ __volatile__ (\			"%0 = w[%1] (z);\n\t"\			: "=d"(__v) : "a"(addr)); (unsigned short)__v; })#define bfin_write16(addr,val) ({\			__asm__ __volatile__ (\			"w[%0] = %1;\n\t"\			: : "a"(addr) , "d"(val) : "memory");})/* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF) */#define bfin_read_TWI_CLKDIV()		bfin_read16(TWI_CLKDIV)#define bfin_write_TWI_CLKDIV(val)	bfin_write16(TWI_CLKDIV,val)#define bfin_read_TWI_CONTROL()		bfin_read16(TWI_CONTROL)#define bfin_write_TWI_CONTROL(val)	bfin_write16(TWI_CONTROL,val)#define bfin_read_TWI_SLAVE_CTL()	bfin_read16(TWI_SLAVE_CTL)#define bfin_write_TWI_SLAVE_CTL(val)	bfin_write16(TWI_SLAVE_CTL,val)#define bfin_read_TWI_SLAVE_STAT()	bfin_read16(TWI_SLAVE_STAT)#define bfin_write_TWI_SLAVE_STAT(val)	bfin_write16(TWI_SLAVE_STAT,val)#define bfin_read_TWI_SLAVE_ADDR()	bfin_read16(TWI_SLAVE_ADDR)#define bfin_write_TWI_SLAVE_ADDR(val)	bfin_write16(TWI_SLAVE_ADDR,val)#define bfin_read_TWI_MASTER_CTL()	bfin_read16(TWI_MASTER_CTL)#define bfin_write_TWI_MASTER_CTL(val)	bfin_write16(TWI_MASTER_CTL,val)#define bfin_read_TWI_MASTER_STAT()	bfin_read16(TWI_MASTER_STAT)#define bfin_write_TWI_MASTER_STAT(val)	bfin_write16(TWI_MASTER_STAT,val)#define bfin_read_TWI_MASTER_ADDR()	bfin_read16(TWI_MASTER_ADDR)#define bfin_write_TWI_MASTER_ADDR(val)	bfin_write16(TWI_MASTER_ADDR,val)#define bfin_read_TWI_INT_STAT()	bfin_read16(TWI_INT_STAT)#define bfin_write_TWI_INT_STAT(val)	bfin_write16(TWI_INT_STAT,val)#define bfin_read_TWI_INT_MASK()	bfin_read16(TWI_INT_MASK)#define bfin_write_TWI_INT_MASK(val)	bfin_write16(TWI_INT_MASK,val)#define bfin_read_TWI_FIFO_CTL()	bfin_read16(TWI_FIFO_CTL)#define bfin_write_TWI_FIFO_CTL(val)	bfin_write16(TWI_FIFO_CTL,val)#define bfin_read_TWI_FIFO_STAT()	bfin_read16(TWI_FIFO_STAT)#define bfin_write_TWI_FIFO_STAT(val)	bfin_write16(TWI_FIFO_STAT,val)#define bfin_read_TWI_XMT_DATA8()	bfin_read16(TWI_XMT_DATA8)#define bfin_write_TWI_XMT_DATA8(val)	bfin_write16(TWI_XMT_DATA8,val)#define bfin_read_TWI_XMT_DATA16()	bfin_read16(TWI_XMT_DATA16)#define bfin_write_TWI_XMT_DATA16(val)	bfin_write16(TWI_XMT_DATA16,val)#define bfin_read_TWI_RCV_DATA8()	bfin_read16(TWI_RCV_DATA8)#define bfin_write_TWI_RCV_DATA8(val)	bfin_write16(TWI_RCV_DATA8,val)#define bfin_read_TWI_RCV_DATA16()	bfin_read16(TWI_RCV_DATA16)#define bfin_write_TWI_RCV_DATA16(val)	bfin_write16(TWI_RCV_DATA16,val)#ifdef DEBUG_I2C#define PRINTD(fmt,args...)	do {	\	if (gd->have_console)		\		printf(fmt ,##args);	\	} while (0)#else#define PRINTD(fmt,args...)#endif#ifndef CONFIG_TWICLK_KHZ#define CONFIG_TWICLK_KHZ	50#endif/* All transfers are described by this data structure */struct i2c_msg {	u16 addr;		/* slave address */	u16 flags;#define I2C_M_STOP		0x2#define I2C_M_RD		0x1	u16 len;		/* msg length */	u8 *buf;		/* pointer to msg data */};/** * i2c_reset: - reset the host controller * */static void i2c_reset(void){	/* Disable TWI */	bfin_write_TWI_CONTROL(0);	sync();	/* Set TWI internal clock as 10MHz */	bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);	/* Set Twi interface clock as specified */	if (CONFIG_TWICLK_KHZ > 400)		bfin_write_TWI_CLKDIV(((5 * 1024 / 400) << 8) | ((5 * 1024 /						400) & 0xFF));	else		bfin_write_TWI_CLKDIV(((5 * 1024 /					CONFIG_TWICLK_KHZ) << 8) | ((5 * 1024 /						CONFIG_TWICLK_KHZ)						& 0xFF));	/* Enable TWI */	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);	sync();}int wait_for_completion(struct i2c_msg *msg, int timeout_count){	unsigned short twi_int_stat;	unsigned short mast_stat;	int i;	for (i = 0; i < timeout_count; i++) {		twi_int_stat = bfin_read_TWI_INT_STAT();		mast_stat = bfin_read_TWI_MASTER_STAT();		if (XMTSERV & twi_int_stat) {			/* Transmit next data */			if (msg->len > 0) {				bfin_write_TWI_XMT_DATA8(*(msg->buf++));				msg->len--;			} else if (msg->flags & I2C_M_STOP)				bfin_write_TWI_MASTER_CTL				    (bfin_read_TWI_MASTER_CTL() | STOP);			sync();			/* Clear status */			bfin_write_TWI_INT_STAT(XMTSERV);			sync();			i = 0;		}		if (RCVSERV & twi_int_stat) {			if (msg->len > 0) {				/* Receive next data */				*(msg->buf++) = bfin_read_TWI_RCV_DATA8();				msg->len--;			} else if (msg->flags & I2C_M_STOP) {				bfin_write_TWI_MASTER_CTL				    (bfin_read_TWI_MASTER_CTL() | STOP);				sync();			}			/* Clear interrupt source */			bfin_write_TWI_INT_STAT(RCVSERV);			sync();			i = 0;		}		if (MERR & twi_int_stat) {			bfin_write_TWI_INT_STAT(MERR);			bfin_write_TWI_INT_MASK(0);			bfin_write_TWI_MASTER_STAT(0x3e);			bfin_write_TWI_MASTER_CTL(0);			sync();			/*			 * if both err and complete int stats are set,			 * return proper results.			 */			if (MCOMP & twi_int_stat) {				bfin_write_TWI_INT_STAT(MCOMP);				bfin_write_TWI_INT_MASK(0);				bfin_write_TWI_MASTER_CTL(0);				sync();				/*				 * If it is a quick transfer,				 * only address bug no data, not an err.				 */				if (msg->len == 0 && mast_stat & BUFRDERR)					return 0;				/*				 * If address not acknowledged return -3,				 * else return 0.				 */				else if (!(mast_stat & ANAK))					return 0;				else					return -3;			}			return -1;		}		if (MCOMP & twi_int_stat) {			bfin_write_TWI_INT_STAT(MCOMP);			sync();			bfin_write_TWI_INT_MASK(0);			bfin_write_TWI_MASTER_CTL(0);			sync();			return 0;		}	}	if (msg->flags & I2C_M_RD)		return -4;	else		return -2;}/** * i2c_transfer: - Transfer one byte over the i2c bus * * This function can tranfer a byte over the i2c bus in both directions. * It is used by the public API functions. * * @return:	 0: transfer successful *		-1: transfer fail *		-2: transmit timeout *		-3: ACK missing *		-4: receive timeout *		-5: controller not ready */int i2c_transfer(struct i2c_msg *msg){	int ret = 0;	int timeout_count = 10000;	int len = msg->len;	if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) {		ret = -5;		goto transfer_error;	}	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) ;	/* Set Transmit device address */	bfin_write_TWI_MASTER_ADDR(msg->addr);	/*	 * FIFO Initiation.	 * Data in FIFO should be discarded before start a new operation.	 */	bfin_write_TWI_FIFO_CTL(0x3);	sync();	bfin_write_TWI_FIFO_CTL(0);	sync();	if (!(msg->flags & I2C_M_RD)) {		/* Transmit first data */		if (msg->len > 0) {			PRINTD("1 in i2c_transfer: buf=%d, len=%d\n", *msg->buf,			       len);			bfin_write_TWI_XMT_DATA8(*(msg->buf++));			msg->len--;			sync();		}	}	/* clear int stat */	bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV);	/* Interrupt mask . Enable XMT, RCV interrupt */	bfin_write_TWI_INT_MASK(MCOMP | MERR |			((msg->flags & I2C_M_RD) ? RCVSERV : XMTSERV));	sync();	if (len > 0 && len <= 255)		bfin_write_TWI_MASTER_CTL((len << 6));	else if (msg->len > 255) {		bfin_write_TWI_MASTER_CTL((0xff << 6));		msg->flags &= I2C_M_STOP;	} else		bfin_write_TWI_MASTER_CTL(0);	/* Master enable */	bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |			((msg->flags & I2C_M_RD)			 ? MDIR : 0) | ((CONFIG_TWICLK_KHZ >					 100) ? FAST : 0));	sync();	ret = wait_for_completion(msg, timeout_count);	PRINTD("3 in i2c_transfer: ret=%d\n", ret);transfer_error:	switch (ret) {	case 1:		PRINTD(("i2c_transfer: error: transfer fail\n"));		break;	case 2:		PRINTD(("i2c_transfer: error: transmit timeout\n"));		break;	case 3:		PRINTD(("i2c_transfer: error: ACK missing\n"));		break;	case 4:		PRINTD(("i2c_transfer: error: receive timeout\n"));		break;	case 5:		PRINTD(("i2c_transfer: error: controller not ready\n"));		i2c_reset();		break;	default:		break;	}	return ret;}/* ---------------------------------------------------------------------*//* API Functions							*//* ---------------------------------------------------------------------*/void i2c_init(int speed, int slaveaddr){	i2c_reset();}/** * i2c_probe: - Test if a chip answers for a given i2c address * * @chip:	address of the chip which is searched for * @return: 	0 if a chip was found, -1 otherwhise */int i2c_probe(uchar chip){	struct i2c_msg msg;	u8 probebuf;	i2c_reset();	probebuf = 0;	msg.addr = chip;	msg.flags = 0;	msg.len = 1;	msg.buf = &probebuf;	if (i2c_transfer(&msg))		return -1;	msg.addr = chip;	msg.flags = I2C_M_RD;	msg.len = 1;	msg.buf = &probebuf;	if (i2c_transfer(&msg))		return -1;	return 0;}/** *   i2c_read: - Read multiple bytes from an i2c device * *   chip:    I2C chip address, range 0..127 *   addr:    Memory (register) address within the chip *   alen:    Number of bytes to use for addr (typically 1, 2 for larger *		memories, 0 for register type devices with only one *		register) *   buffer:  Where to read/write the data *   len:     How many bytes to read/write * *   Returns: 0 on success, not 0 on failure */int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len){	struct i2c_msg msg;	u8 addr_bytes[3];	/* lowest...highest byte of data address */	PRINTD("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x\n", chip,			addr, alen, len);	if (alen > 0) {		addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF);		addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF);		addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF);		msg.addr = chip;		msg.flags = 0;		msg.len = alen;		msg.buf = addr_bytes;		if (i2c_transfer(&msg))			return -1;	}	/* start read sequence */	PRINTD(("i2c_read: start read sequence\n"));	msg.addr = chip;	msg.flags = I2C_M_RD;	msg.len = len;	msg.buf = buffer;	if (i2c_transfer(&msg))		return -1;	return 0;}/** *   i2c_write: -  Write multiple bytes to an i2c device * *   chip:    I2C chip address, range 0..127 *   addr:    Memory (register) address within the chip *   alen:    Number of bytes to use for addr (typically 1, 2 for larger *		memories, 0 for register type devices with only one *		register) *   buffer:  Where to read/write the data *   len:     How many bytes to read/write * *   Returns: 0 on success, not 0 on failure */int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len){	struct i2c_msg msg;	u8 addr_bytes[3];	/* lowest...highest byte of data address */	PRINTD		("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x, buf0=0x%x\n",		 chip, addr, alen, len, buffer[0]);	/* chip address write */	if (alen > 0) {		addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF);		addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF);		addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF);		msg.addr = chip;		msg.flags = 0;		msg.len = alen;		msg.buf = addr_bytes;		if (i2c_transfer(&msg))			return -1;	}	/* start read sequence */	PRINTD(("i2c_write: start write sequence\n"));	msg.addr = chip;	msg.flags = 0;	msg.len = len;	msg.buf = buffer;	if (i2c_transfer(&msg))		return -1;	return 0;}uchar i2c_reg_read(uchar chip, uchar reg){	uchar buf;	PRINTD("i2c_reg_read: chip=0x%02x, reg=0x%02x\n", chip, reg);	i2c_read(chip, reg, 0, &buf, 1);	return (buf);}void i2c_reg_write(uchar chip, uchar reg, uchar val){	PRINTD("i2c_reg_write: chip=0x%02x, reg=0x%02x, val=0x%02x\n", chip,			reg, val);	i2c_write(chip, reg, 0, &val, 1);}#endif				/* CONFIG_HARD_I2C */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -