#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