in busses/i2c-jz4780.c [434:555]
static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
{
unsigned short tmp;
unsigned short intst;
unsigned short intmsk;
struct jz4780_i2c *i2c = dev_id;
spin_lock(&i2c->lock);
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
intst &= intmsk;
if (intst & JZ4780_I2C_INTST_TXABT) {
jz4780_i2c_trans_done(i2c);
goto done;
}
if (intst & JZ4780_I2C_INTST_RXOF) {
dev_dbg(&i2c->adap.dev, "received fifo overflow!\n");
jz4780_i2c_trans_done(i2c);
goto done;
}
/*
* When reading, always drain RX FIFO before we send more Read
* Commands to avoid fifo overrun
*/
if (i2c->is_write == 0) {
int rd_left;
while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA)
& JZ4780_I2C_STA_RFNE)) {
*(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC)
& 0xff;
i2c->rd_data_xfered++;
if (i2c->rd_data_xfered == i2c->rd_total_len) {
jz4780_i2c_trans_done(i2c);
goto done;
}
}
rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
if (rd_left <= i2c->cdata->fifosize)
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
}
if (intst & JZ4780_I2C_INTST_TXEMP) {
if (i2c->is_write == 0) {
int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
int max_send = (i2c->cdata->fifosize - 1)
- (i2c->rd_cmd_xfered
- i2c->rd_data_xfered);
int cmd_to_send = min(cmd_left, max_send);
if (i2c->rd_cmd_xfered != 0)
cmd_to_send = min(cmd_to_send,
i2c->cdata->fifosize
- i2c->cdata->tx_level - 1);
if (cmd_to_send) {
i2c->rd_cmd_xfered += cmd_to_send;
cmd_left = i2c->rd_total_len -
i2c->rd_cmd_xfered;
jz4780_i2c_send_rcmd(i2c,
cmd_to_send, cmd_left);
}
if (cmd_left == 0) {
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
if (i2c->cdata->version < ID_X1000) {
tmp = jz4780_i2c_readw(i2c,
JZ4780_I2C_CTRL);
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
jz4780_i2c_writew(i2c,
JZ4780_I2C_CTRL, tmp);
}
}
} else {
unsigned short data;
unsigned short i2c_sta;
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
(i2c->wt_len > 0)) {
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
data = *i2c->wbuf;
data &= ~JZ4780_I2C_DC_READ;
if ((i2c->wt_len == 1) && (!i2c->stop_hold) &&
(i2c->cdata->version >= ID_X1000))
data |= X1000_I2C_DC_STOP;
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, data);
i2c->wbuf++;
i2c->wt_len--;
}
if (i2c->wt_len == 0) {
if ((!i2c->stop_hold) && (i2c->cdata->version <
ID_X1000)) {
tmp = jz4780_i2c_readw(i2c,
JZ4780_I2C_CTRL);
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
jz4780_i2c_writew(i2c,
JZ4780_I2C_CTRL, tmp);
}
jz4780_i2c_trans_done(i2c);
goto done;
}
}
}
done:
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}