static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) { u8 ack; if (isr == 0) { if (state != state_stop) { DBG("KW: Timeout !\n"); *rc = -EIO; goto stop; } if (state == state_stop) { ack = kw_read_reg(reg_status); if (!(ack & KW_I2C_STAT_BUSY)) { state = state_idle; kw_write_reg(reg_ier, 0x00); } } return state; } if (isr & KW_I2C_IRQ_ADDR) { ack = kw_read_reg(reg_status); if (state != state_addr) { kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); WRONG_STATE("KW_I2C_IRQ_ADDR"); *rc = -EIO; goto stop; } if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { *rc = -ENODEV; DBG("KW: NAK on address\n"); return state_stop; } else { if (rw) { state = state_read; if (*len > 1) kw_write_reg(reg_control, KW_I2C_CTL_AAK); } else { state = state_write; kw_write_reg(reg_data, **data); (*data)++; (*len)--; } } kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); } if (isr & KW_I2C_IRQ_DATA) { if (state == state_read) { **data = kw_read_reg(reg_data); (*data)++; (*len)--; kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); if ((*len) == 0) state = state_stop; else if ((*len) == 1) kw_write_reg(reg_control, 0); } else if (state == state_write) { ack = kw_read_reg(reg_status); if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { DBG("KW: nack on data write\n"); *rc = -EIO; goto stop; } else if (*len) { kw_write_reg(reg_data, **data); (*data)++; (*len)--; } else { kw_write_reg(reg_control, KW_I2C_CTL_STOP); state = state_stop; *rc = 0; } kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); } else { kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); WRONG_STATE("KW_I2C_IRQ_DATA"); if (state != state_stop) { *rc = -EIO; goto stop; } } } if (isr & KW_I2C_IRQ_STOP) { kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); if (state != state_stop) { WRONG_STATE("KW_I2C_IRQ_STOP"); *rc = -EIO; } return state_idle; } if (isr & KW_I2C_IRQ_START) kw_write_reg(reg_isr, KW_I2C_IRQ_START); return state; stop: kw_write_reg(reg_control, KW_I2C_CTL_STOP); return state_stop; }
/* Main state machine for standard & standard sub mode */ static void handle_interrupt(struct keywest_iface *iface, u8 isr) { int ack; if (isr == 0) { if (iface->state != state_stop) { pr_debug("KW: Timeout !\n"); do_stop(iface, -EIO); } if (iface->state == state_stop) { ack = read_reg(reg_status); if (!(ack & KW_I2C_STAT_BUSY)) { iface->state = state_idle; write_reg(reg_ier, 0x00); #ifndef POLLED_MODE complete(&iface->complete); #endif /* POLLED_MODE */ } } return; } if (isr & KW_I2C_IRQ_ADDR) { ack = read_reg(reg_status); if (iface->state != state_addr) { write_reg(reg_isr, KW_I2C_IRQ_ADDR); WRONG_STATE("KW_I2C_IRQ_ADDR"); do_stop(iface, -EIO); return; } if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { iface->state = state_stop; iface->result = -ENODEV; pr_debug("KW: NAK on address\n"); } else { /* Handle rw "quick" mode */ if (iface->datalen == 0) { do_stop(iface, 0); } else if (iface->read_write == I2C_SMBUS_READ) { iface->state = state_read; if (iface->datalen > 1) write_reg(reg_control, KW_I2C_CTL_AAK); } else { iface->state = state_write; write_reg(reg_data, *(iface->data++)); iface->datalen--; } } write_reg(reg_isr, KW_I2C_IRQ_ADDR); } if (isr & KW_I2C_IRQ_DATA) { if (iface->state == state_read) { *(iface->data++) = read_reg(reg_data); write_reg(reg_isr, KW_I2C_IRQ_DATA); iface->datalen--; if (iface->datalen == 0) iface->state = state_stop; else if (iface->datalen == 1) write_reg(reg_control, 0); } else if (iface->state == state_write) { /* Check ack status */ ack = read_reg(reg_status); if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { pr_debug("KW: nack on data write (%x): %x\n", iface->data[-1], ack); do_stop(iface, -EIO); } else if (iface->datalen) { write_reg(reg_data, *(iface->data++)); iface->datalen--; } else { write_reg(reg_control, KW_I2C_CTL_STOP); iface->state = state_stop; iface->result = 0; } write_reg(reg_isr, KW_I2C_IRQ_DATA); } else { write_reg(reg_isr, KW_I2C_IRQ_DATA); WRONG_STATE("KW_I2C_IRQ_DATA"); if (iface->state != state_stop) do_stop(iface, -EIO); } } if (isr & KW_I2C_IRQ_STOP) { write_reg(reg_isr, KW_I2C_IRQ_STOP); if (iface->state != state_stop) { WRONG_STATE("KW_I2C_IRQ_STOP"); iface->result = -EIO; } iface->state = state_idle; write_reg(reg_ier, 0x00); #ifndef POLLED_MODE complete(&iface->complete); #endif /* POLLED_MODE */ } if (isr & KW_I2C_IRQ_START) write_reg(reg_isr, KW_I2C_IRQ_START); }