static irqreturn_t s3c6410_i2c_xfer_irq(int irq, void *dev_id)
{
    unsigned char byte;
    unsigned long tmp;
	unsigned int iicSt = readl(s3c6410_i2c_xfer_data.regs + S3C2410_IICSTAT);
    //iicSt  = s3c6410_i2c_regs->iicstat; 

	if(iicSt & S3C2410_IICSTAT_ARBITR) 
        printk("Bus arbitration failed\n\r");

	switch (s3c6410_i2c_xfer_data.state) {
    case STATE_START : /* 发出S和设备地址后,产生中断 */
	{
		AT24CXX_DBG("Start\n");
		/* 如果没有ACK, 返回错误 */
		if (iicSt & S3C2410_IICSTAT_LASTBIT) {
			s3c6410_i2c_stop(-ENODEV);
			break;
		}

		if (isLastMsg() && isEndData()) {
			s3c6410_i2c_stop(0);
			break;
		}

		/* 进入下一个状态 */
		if (s3c6410_i2c_xfer_data.msgs->flags & I2C_M_RD) { /* 读 */ 
			s3c6410_i2c_xfer_data.state = STATE_READ;
			goto next_read;
		}else {
			s3c6410_i2c_xfer_data.state = STATE_WRITE;
		}	
	}

	case STATE_WRITE: {
		AT24CXX_DBG("STATE_WRITE\n");
		/* 如果没有ACK, 返回错误 */
		if (iicSt & S3C2410_IICSTAT_LASTBIT) {
			s3c6410_i2c_stop(-ENODEV);
			break;
		}

		if (!isEndData()) { /* 如果当前msg还有数据要发送 */
            byte = s3c6410_i2c_xfer_data.msgs->buf[s3c6410_i2c_xfer_data.cur_ptr];
            writeb(byte, s3c6410_i2c_xfer_data.regs + S3C2410_IICDS);
			//s3c6410_i2c_regs->iicds = s3c6410_i2c_xfer_data.msgs->buf[s3c6410_i2c_xfer_data.cur_ptr];
			s3c6410_i2c_xfer_data.cur_ptr++;
			
			// 将数据写入IICDS后,需要一段时间才能出现在SDA线上
			ndelay(50);	

            tmp = readl(s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
            /* tmp = 0xaf */
            tmp = S3C2410_IICCON_ACKEN | S3C2410_IICCON_TXDIV_16 | S3C2410_IICCON_IRQEN | S3C2410_IICCON_SCALEMASK;  
            writel(tmp, s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
			//s3c6410_i2c_regs->iiccon = 0xaf;		// 恢复I2C传输
			break;				
		}else if (!isLastMsg()) {
			/* 开始处理下一个消息 */
			s3c6410_i2c_xfer_data.msgs++;
			s3c6410_i2c_xfer_data.cur_msg++;
			s3c6410_i2c_xfer_data.cur_ptr = 0;
			s3c6410_i2c_xfer_data.state = STATE_START;
			/* 发出START信号和发出设备地址 */
			s3c6410_i2c_start();
			break;
		}else {
			/* 是最后一个消息的最后一个数据 */
			s3c6410_i2c_stop(0);
			break;				
		}

		break;
	}

	case STATE_READ: {
		AT24CXX_DBG("STATE_READ\n");
		/* 读出数据 */
		//s3c6410_i2c_xfer_data.msgs->buf[s3c6410_i2c_xfer_data.cur_ptr] = s3c6410_i2c_regs->iicds;			
        byte = readb(s3c6410_i2c_xfer_data.regs + S3C2410_IICDS);
        s3c6410_i2c_xfer_data.msgs->buf[s3c6410_i2c_xfer_data.cur_ptr] = byte;			
		s3c6410_i2c_xfer_data.cur_ptr++;
next_read:
		if (!isEndData()) { /* 如果数据没读写, 继续发起读操作 */
			if (isLastData()) { /* 如果即将读的数据是最后一个, 不发ack */
                tmp = readl(s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
                /* tmp = 0x2f */
                tmp = S3C2410_IICCON_IRQEN | S3C2410_IICCON_SCALEMASK;
                writel(tmp, s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
                //s3c6410_i2c_regs->iiccon = 0x2f;   // 恢复I2C传输,接收到下一数据时无ACK
			}else {
                tmp = readl(s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);                    
                /* tmp = 0xaf */
                tmp = S3C2410_IICCON_ACKEN | S3C2410_IICCON_TXDIV_16 | S3C2410_IICCON_IRQEN | S3C2410_IICCON_SCALEMASK;  
                writel(tmp, s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
				//s3c6410_i2c_regs->iiccon = 0xaf;   // 恢复I2C传输,接收到下一数据时发出ACK
			}				
			break;
		}else if (!isLastMsg()) {
			/* 开始处理下一个消息 */
			s3c6410_i2c_xfer_data.msgs++;
			s3c6410_i2c_xfer_data.cur_msg++;
			s3c6410_i2c_xfer_data.cur_ptr = 0;
			s3c6410_i2c_xfer_data.state = STATE_START;
			/* 发出START信号和发出设备地址 */
			s3c6410_i2c_start();
			break;
		}else {
			/* 是最后一个消息的最后一个数据 */
			s3c6410_i2c_stop(0);
			break;								
		}
		break;
	}

	default: break;
	}

	/* 清中断 */
    tmp = readl(s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
    writel(tmp & ~(S3C2410_IICCON_IRQPEND), s3c6410_i2c_xfer_data.regs + S3C2410_IICCON);
	//s3c6410_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);

	return IRQ_HANDLED;	
}
Beispiel #2
0
static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
{
	 unsigned int iicst;
	 
	 iicst = s3c2440_i2c_regs->iicstat;
	 if(iicst & 0x08){printk("s3c2440 i2c Bus arbitration failed\n\r");}

	 switch(s3c2440_i2c_xfer_data.state)
	 {
		case STATE_START:		//发出START和设备地址后产生中断
		{	
			//如果没有ACK,返回错误
			if (iicst & S3C2410_IICSTAT_LASTBIT)
			{
				s3c2440_i2c_stop(-ENODEV);
				break;
			}
			if(isLastMsg() && isEndData())
			{
				s3c2440_i2c_stop(0);
				break;
			}

			//进入下一个状态
			if(s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD)		//read
			{
				s3c2440_i2c_xfer_data.state = STATE_READ;
				goto next_read;
			}
			else
			{
				s3c2440_i2c_xfer_data.state = STATE_WRITE;
			}
		}
		case STATE_WRITE:
		{	
			//如果没有ACK,返回错误
			if (iicst & S3C2410_IICSTAT_LASTBIT)
			{
				s3c2440_i2c_stop(-ENODEV);
				break;
			}
			if(!isEndData())	//如果当前msg还有数据要发送
			{
				s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];
				s3c2440_i2c_xfer_data.cur_ptr++;
				ndelay(50);
				s3c2440_i2c_regs->iiccon = 0xaf;		//恢复I2C传输
				break;
			}
			else if(!isLastMsg())
			{
				//开始处理下一个消息
				s3c2440_i2c_xfer_data.msgs++;
				s3c2440_i2c_xfer_data.cur_msg++;
				s3c2440_i2c_xfer_data.cur_ptr=0;
				s3c2440_i2c_xfer_data.state = STATE_START;

				//发出START信号和发出设备地址
				s3c2440_i2c_start();
				break;
			}
			else
			{
				//如果是最后一个消息的最后一个数据
				s3c2440_i2c_stop(0);
				break;
			}
			break;
		}
		case STATE_READ:
		{	
			//读出数据
			s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;
			s3c2440_i2c_xfer_data.cur_ptr++;
			
next_read:		
			if(!isEndData())
			{
				//如果数据没读完,继续发起读操作
				if(isLastData())		//如果即将读的数据是最后一个,那么不发ACK
				{
					s3c2440_i2c_regs->iiccon = 0x2f;
				}
				else
				{
					s3c2440_i2c_regs->iiccon = 0xaf;
				}
				break;
			}
			else if(!isLastMsg())
			{
				//开始处理下一个消息
				s3c2440_i2c_xfer_data.msgs++;
				s3c2440_i2c_xfer_data.cur_msg++;
				s3c2440_i2c_xfer_data.cur_ptr=0;
				s3c2440_i2c_xfer_data.state = STATE_START;

				//发出START信号和发出设备地址
				s3c2440_i2c_start();
				break;
			}
			else
			{
				//如果是最后一个消息的最后一个数据
				s3c2440_i2c_stop(0);
				break;
			}
			break;
		}
		default: break;
	 }

	//清中断
	s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);

	 return IRQ_HANDLED;
}