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; }
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; }