static void rk30_irq_write_prepare(struct rk30_i2c *i2c) { unsigned int data = 0, cnt = 0, i, j; unsigned char byte; if(is_msgend(i2c)) { rk30_i2c_stop(i2c, i2c->error); return; } for(i = 0; i < 8; i++) { data = 0; for(j = 0; j < 4; j++) { if(is_msgend(i2c)) break; if(i2c->msg_ptr == 0 && cnt == 0) byte = (i2c->addr & 0x7f) << 1; else byte = i2c->msg->buf[i2c->msg_ptr++]; cnt++; data |= (byte << (j * 8)); } i2c_writel(data, i2c->regs + I2C_TXDATA_BASE + 4 * i); if(is_msgend(i2c)) break; } i2c_writel(cnt, i2c->regs + I2C_MTXCNT); }
static void rk30_irq_read_prepare(struct rk30_i2c *i2c) { unsigned int cnt, len = i2c->msg->len - i2c->msg_ptr; if(len <= 32 && i2c->msg_ptr != 0) rk30_set_rx_mode(i2c, 1); else if(i2c->msg_ptr != 0) rk30_set_rx_mode(i2c, 0); if(is_msgend(i2c)) { rk30_i2c_stop(i2c, i2c->error); return; } if(len > 32) cnt = 32; else cnt = len; i2c_writel(cnt, i2c->regs + I2C_MRXCNT); }
static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id) { struct synquacer_i2c *i2c = dev_id; unsigned char byte; unsigned char bsr, bcr; int ret; bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR); bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr); if (bcr & SYNQUACER_I2C_BCR_BER) { dev_err(i2c->dev, "bus error\n"); synquacer_i2c_stop(i2c, -EAGAIN); goto out; } if ((bsr & SYNQUACER_I2C_BSR_AL) || !(bcr & SYNQUACER_I2C_BCR_MSS)) { dev_dbg(i2c->dev, "arbitration lost\n"); synquacer_i2c_stop(i2c, -EAGAIN); goto out; } switch (i2c->state) { case STATE_START: if (bsr & SYNQUACER_I2C_BSR_LRB) { dev_dbg(i2c->dev, "ack was not received\n"); synquacer_i2c_stop(i2c, -EAGAIN); goto out; } if (i2c->msg->flags & I2C_M_RD) i2c->state = STATE_READ; else i2c->state = STATE_WRITE; if (is_lastmsg(i2c) && i2c->msg->len == 0) { synquacer_i2c_stop(i2c, 0); goto out; } if (i2c->state == STATE_READ) goto prepare_read; /* fall through */ case STATE_WRITE: if (bsr & SYNQUACER_I2C_BSR_LRB) { dev_dbg(i2c->dev, "WRITE: No Ack\n"); synquacer_i2c_stop(i2c, -EAGAIN); goto out; } if (!is_msgend(i2c)) { writeb(i2c->msg->buf[i2c->msg_ptr++], i2c->base + SYNQUACER_I2C_REG_DAR); /* clear IRQ, and continue */ writeb(SYNQUACER_I2C_BCR_BEIE | SYNQUACER_I2C_BCR_MSS | SYNQUACER_I2C_BCR_INTE, i2c->base + SYNQUACER_I2C_REG_BCR); break; } if (is_lastmsg(i2c)) { synquacer_i2c_stop(i2c, 0); break; } dev_dbg(i2c->dev, "WRITE: Next Message\n"); i2c->msg_ptr = 0; i2c->msg_idx++; i2c->msg++; /* send the new start */ ret = synquacer_i2c_master_start(i2c, i2c->msg); if (ret < 0) { dev_dbg(i2c->dev, "restart error (%d)\n", ret); synquacer_i2c_stop(i2c, -EAGAIN); break; } i2c->state = STATE_START; break; case STATE_READ: byte = readb(i2c->base + SYNQUACER_I2C_REG_DAR); if (!(bsr & SYNQUACER_I2C_BSR_FBT)) /* data */ i2c->msg->buf[i2c->msg_ptr++] = byte; else /* address */ dev_dbg(i2c->dev, "address:0x%02x. ignore it.\n", byte); prepare_read: if (is_msglast(i2c)) { writeb(SYNQUACER_I2C_BCR_MSS | SYNQUACER_I2C_BCR_BEIE | SYNQUACER_I2C_BCR_INTE, i2c->base + SYNQUACER_I2C_REG_BCR); break; } if (!is_msgend(i2c)) { writeb(SYNQUACER_I2C_BCR_MSS | SYNQUACER_I2C_BCR_BEIE | SYNQUACER_I2C_BCR_INTE | SYNQUACER_I2C_BCR_ACK, i2c->base + SYNQUACER_I2C_REG_BCR); break; } if (is_lastmsg(i2c)) { /* last message, send stop and complete */ dev_dbg(i2c->dev, "READ: Send Stop\n"); synquacer_i2c_stop(i2c, 0); break; } dev_dbg(i2c->dev, "READ: Next Transfer\n"); i2c->msg_ptr = 0; i2c->msg_idx++; i2c->msg++; ret = synquacer_i2c_master_start(i2c, i2c->msg); if (ret < 0) { dev_dbg(i2c->dev, "restart error (%d)\n", ret); synquacer_i2c_stop(i2c, -EAGAIN); } else { i2c->state = STATE_START; } break; default: dev_err(i2c->dev, "called in err STATE (%d)\n", i2c->state); break; } out: WAIT_PCLK(10, i2c->pclkrate); return IRQ_HANDLED; }