为lpc3250 uboot-1.3.3 添加i2c命令(imd,imw,iprobe等)

#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

你可能感兴趣的:(为lpc3250 uboot-1.3.3 添加i2c命令(imd,imw,iprobe等))