#include <common.h>
#ifdef CONFIG_HARD_I2C
#ifdef CONFIG_LPC3250_I2C
#include <command.h>
#include <i2c.h>
#include <asm/io.h>
#include <linux/string.h>
/* I2C register definitions */
#define I2C1_BASE_ADDR 0x400A0000
#define I2C2_BASE_ADDR 0x400A8000
#define I2C_RX (I2C2_BASE_ADDR + 0x00) /* I2C Rx Data FIFO */
#define I2C_TX (I2C2_BASE_ADDR + 0x00) /* I2C Tx Data FIFO */
#define I2C_STAT (I2C2_BASE_ADDR + 0x04) /* I2C Status Register */
#define I2C_CTRL (I2C2_BASE_ADDR + 0x08) /* I2C Control Register */
#define I2C_CLK_HI (I2C2_BASE_ADDR + 0x0c) /* I2C Clock Divider high */
#define I2C_CLK_LO (I2C2_BASE_ADDR + 0x10) /* I2C Clock Divider low */
#define I2C_ADDR (I2C2_BASE_ADDR + 0x14) /* I2C Slave Address */
#define I2C_RXFL (I2C2_BASE_ADDR + 0x18) /* I2C Rx FIFO level */
#define I2C_TXFL (I2C2_BASE_ADDR + 0x1c) /* I2C Tx FIFO level */
#define I2C_RXB (I2C2_BASE_ADDR + 0x20) /* I2C Number of bytes received */
#define I2C_TXB (I2C2_BASE_ADDR + 0x24) /* I2C Number of bytes transmitted */
#define I2C_STX (I2C2_BASE_ADDR + 0x28) /* Slave Transmit FIFO */
#define I2C_STXFL (I2C2_BASE_ADDR + 0x2c) /* Slave Transmit FIFO level */
/* I2C STATE register definitions */
#define I2C_TDI (1<<0) /* Transaction Done Interrupt */
#define I2C_AFI (1<<1) /* Arbitration Failure Interrupt*/
#define I2C_NAI (1<<2) /* No Acknowledge Interrupt */
#define I2C_DRMI (1<<3) /* Master Data Request Interrupt*/
#define I2C_DRSI (1<<4) /* Slave Data Request Interrupt */
#define I2C_ACTIVE (1<<5) /* Busy bus indicator */
#define I2C_SCL (1<<6) /* The current SCL signal value */
#define I2C_SDA (1<<7) /* The current SDA signal value */
#define I2C_RFF (1<<8) /* Receive FIFO Full */
#define I2C_RFE (1<<9) /* Receive FIFO Empty */
#define I2C_TFF (1<<10) /* Transmit FIFO Full */
#define I2C_TFE (1<<11) /* Transmit FIFO Empty */
#define I2C_TFFS (1<<12) /* Slave Transmit FIFO Full */
#define I2C_TFES (1<<13) /* Slave Transmit FIFO Empty */
/* I2C CTRL register definitions */
#define I2C_CTRL_RESET (1<<8)
/* I2C CLOCK register definitions */
#define I2CCLK_CTRL 0x400040ac
#define I2C_CLK_100K 1
#define I2C_CLK_400K 4
#define I2C_START (1<<8) /* generate a START before this B*/
#define I2C_STOP (1<<9) /* generate a STOP after this B */
#define LPC3250_ADDR_WRITE(a) ( a << 1 | 0 )
#define LPC3250_ADDR_READ(a) ( a << 1 | 1 )
typedef unsigned char uint_8;
typedef unsigned short uint_16;
typedef unsigned int uint_32;
typedef signed char int_8;
typedef signed short int_16;
typedef signed int int_32;
static unsigned int speed = 0;
/****************
在LPC3250中
使用轮询进行i2c传输,不需要使能中断,
即不用设置I2C_CTRL寄存器中的各个中断标志位。
只需要去读I2C_STAT寄存器中的各个状态标志位,来判断i2c传输的各个状态
******************/
int lpc3250_i2c_wait_reset(int timeout)
{
int i;
while(timeout > 0 && ( __raw_readl(I2C_CTRL) & I2C_CTRL_RESET))//等待复位
{
for (i = 1000000 ; i > 0; i--);
timeout--;
}
return (timeout <= 0);
}
void lpc3250_i2c_init(uint_8 i2c_clk)
{
/* I2C2 Clk Ctrl */
//使能i2c2 时钟
__raw_writel(__raw_readl(I2CCLK_CTRL) | (1<<1), I2CCLK_CTRL);
/* 设置I2C时钟为100K */
if (i2c_clk == I2C_CLK_100K)
{
/* HCLK = 104M */
__raw_writel(520, I2C_CLK_HI);
__raw_writel(520, I2C_CLK_LO);
speed = 100 * 1000;
}
/* 设置I2C时钟为400K */
else if (i2c_clk == I2C_CLK_400K)
{
/* HCLK = 104M */
__raw_writel(96, I2C_CLK_HI);
__raw_writel(166, I2C_CLK_LO);
speed = 400 * 1000;
}
/* Reset I2C */
__raw_writel(__raw_readl(I2C_CTRL) | I2C_CTRL_RESET, I2C_CTRL);
lpc3250_i2c_wait_reset(1000);
}
uint_8 lpc3250_i2c_read_direct_len(uchar chip,uint_8 * readBuf,uint_8 len)
{
int n = 0;
int i;
//写从机地址和S信号
__raw_writel(LPC3250_ADDR_READ(chip) | I2C_START, I2C_TX);
/*
在读RX FIFO之前,必须向TX FIFO写一个dummy byte(伪字符)
否则,RX FIFO中会没有数据,即 I2C_RFE = 1
*/
__raw_writel( 0xff , I2C_TX);
for(i=0;i<len;i++) {
if (__raw_readl(I2C_STAT) & I2C_RFE) { //RX FIFO 没有数据
__raw_writel( 0xff , I2C_TX);// wirte a dummy bite
}
//printf("start read RX\n");
//等待RX非空,之前printf可以实现是因为printf执行相当于延时 n = 0;
while ((__raw_readl(I2C_STAT) & I2C_RFE) && (n++ <100000));
if(n>=100000)
{
printf("%s : I2C_RFE == 1\n",__func__);
return -1;
}
readBuf[i] = (uint_8)(__raw_readl(I2C_RX) & 0xff);
/* 清除I2C_TDI,为下一次的P信号做准备 */
__raw_writel(__raw_readl(I2C_STAT) | I2C_TDI,I2C_STAT);
}
//写P信号
__raw_writel(I2C_STOP, I2C_TX);
//产生stop后,TDI 被置位
n =0;
while( (!(__raw_readl(I2C_STAT) & I2C_TDI)) && (n++ <100000)); /* 等待发送完毕 */
if(n>=100000)
{
printf("%s : I2C_TDI == 0\n",__func__);
return -1;
}
/* 清除I2C_TDI,为下一次的P信号做准备 */
__raw_writel(__raw_readl(I2C_STAT) | I2C_TDI,I2C_STAT); /* 清除标志位 */
//复位i2c,清TX/RX FIFO,防止影响下一次的读写
__raw_writel(__raw_readl(I2C_CTRL) | (1<<8), I2C_CTRL);
lpc3250_i2c_wait_reset(1000);
return 0;
}
uint_8 lpc3250_i2c_write_direct_len(uchar chip,uint_8 * writeBuf,int len)
{
int n = 0,i;
__raw_writel(LPC3250_ADDR_WRITE(chip) | I2C_START, I2C_TX);
while ((__raw_readl(I2C_STAT) & I2C_DRMI) && n++ <100000);
if(n>=100000)
{
printf("%s : I2C_DRMI == 1\n",__func__);
return -1;
}
for(i=0;i< len - 1;i++) {
n = 0;
while ((__raw_readl(I2C_STAT) & I2C_TFF)&& n++ <100000); //等待TX FIFO非满
if(n>=100000)
{
printf("%s : I2C_TFF == 1\n",__func__);
return -1;
}
__raw_writel(writeBuf[i], I2C_TX);
}
//重要,缺少这行 会阻塞。之前没有问题是因为printf函数占用了时间,相当于延时
n = 0;
while ((__raw_readl(I2C_STAT) & I2C_TFF)&& n++ <100000);//等待TX FIFO非满
if(n>=100000)
{
printf("%s : I2C_TFF == 1\n",__func__);
return -1;
}
//写最后一个字节和P
__raw_writel((uint_16)(writeBuf[len - 1] | I2C_STOP), I2C_TX);
//当P发送成功后,I2C_TDI被置1
n = 0;
while( !(__raw_readl(I2C_STAT) & I2C_TDI) && n++ <100000); /* 等待发送完毕 */
if(n>=100000)
{
printf("%s : I2C_TDI == 0\n",__func__);
return -1;
}
/* 清除I2C_TDI,为下一次的P信号做准备 */
__raw_writel(__raw_readl(I2C_STAT) | I2C_TDI,I2C_STAT);
//复位i2c,清TX/RX FIFO,防止影响下一次的读写
__raw_writel(__raw_readl(I2C_CTRL) | (1<<8), I2C_CTRL);
lpc3250_i2c_wait_reset(1000);
return 0;
}
int lpc3250_i2c_Write(uchar chip,char *writebuf, int len)
{
return lpc3250_i2c_write_direct_len(chip,writebuf, len);
}
int lpc3250_i2c_Read(uchar chip ,char *writebuf,
int writelen, char *readbuf, int readlen)
{
int ret;
ret = lpc3250_i2c_write_direct_len(chip,writebuf, writelen);
ret = lpc3250_i2c_read_direct_len(chip,readbuf, readlen);
return ret;
}
void i2c_init(int speed, int slaveadd)
{
lpc3250_i2c_init( speed );
}
int i2c_read (uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint_8 addrBuf = addr;
return lpc3250_i2c_Read(chip,&addrBuf, 1, buffer, len);
}
int i2c_write (uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint_8 buf = addr;
strcat(&buf, buffer);
return lpc3250_i2c_write_direct_len(chip,&buf, len + 1 );
}
//成功返回0,失败返回非零值
int i2c_probe(uchar chip)
{
int n = 0;
int ret= 1;
//写从机地址和S信号
__raw_writel(LPC3250_ADDR_READ(chip) | I2C_START, I2C_TX);
/*
在读RX FIFO之前,必须向TX FIFO写一个dummy byte(伪字符)
否则,RX FIFO中会没有数据,即 I2C_RFE = 1
*/
__raw_writel( 0xff , I2C_TX);
while ((!(__raw_readl(I2C_STAT) & I2C_NAI)) && (n++ <1000));//I2C_NAI == 1,NO ACK时跳出循环,说明该地址无设备
if(n>=1000)
{
//printf("%s : I2C_NAI == 1\n",__func__);
ret = 0;//I2C_NAI == 0,说明有响应 该地址有设备
}
/* 清除I2C_TDI,为下一次的P信号做准备 */
__raw_writel(__raw_readl(I2C_STAT) | I2C_TDI,I2C_STAT); /* 清除标志位 */
//复位i2c,清TX/RX FIFO,防止影响下一次的读写
__raw_writel(__raw_readl(I2C_CTRL) | (1<<8), I2C_CTRL);
lpc3250_i2c_wait_reset(1000);
return ret;
}
unsigned int i2c_get_bus_speed(void)
{
return speed;
}
int i2c_set_bus_speed(unsigned int speed)
{
if(speed == 100 * 1000)
{
i2c_init(I2C_CLK_100K, 0);
} else if(speed == 400 * 1000)
{
i2c_init(I2C_CLK_400K, 0);
} else {
printf("speed %d is not supported!\n",speed);
return -1;
}
return 0;
}
#endif
#endif