static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) { struct platform_device *dev = dev_id; struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); unsigned char sr; int wakeup; sr = ioread8(ICSR(pd)); pd->sr |= sr; /* remember state */ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, (pd->msg->flags & I2C_M_RD) ? "read" : "write", pd->pos, pd->msg->len); if (sr & (ICSR_AL | ICSR_TACK)) { /* don't interrupt transaction - continue to issue stop */ iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd)); wakeup = 0; } else if (pd->msg->flags & I2C_M_RD) wakeup = sh_mobile_i2c_isr_rx(pd); else wakeup = sh_mobile_i2c_isr_tx(pd); if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ iowrite8(sr & ~ICSR_WAIT, ICSR(pd)); if (wakeup) { pd->sr |= SW_DONE; wake_up(&pd->wait); } return IRQ_HANDLED; }
static void deactivate_ch(struct sh_mobile_i2c_data *pd) { /* Clear/disable interrupts */ iowrite8(0, ICSR(pd)); iowrite8(0, ICIC(pd)); /* Disable channel */ iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); /* Disable clock */ clk_disable(pd->clk); }
static void deactivate_ch(struct sh_mobile_i2c_data *pd) { /* Clear/disable interrupts */ iowrite8(0, ICSR(pd)); iowrite8(0, ICIC(pd)); /* Disable channel */ iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); /* Disable clock and mark device as idle */ clk_disable(pd->clk); pm_runtime_put_sync(pd->dev); }
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter); struct i2c_msg *msg; int err = 0; u_int8_t val; int i, k, retry_count; activate_ch(pd); /* Process all messages */ for (i = 0; i < num; i++) { msg = &msgs[i]; err = start_ch(pd, msg); if (err) break; i2c_op(pd, OP_START, 0); /* The interrupt handler takes care of the rest... */ k = wait_event_timeout(pd->wait, pd->sr & (ICSR_TACK | SW_DONE), 5 * HZ); if (!k) dev_err(pd->dev, "Transfer request timed out\n"); retry_count = 1000; again: val = ioread8(ICSR(pd)); dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); /* the interrupt handler may wake us up before the * transfer is finished, so poll the hardware * until we're done. */ if (val & ICSR_BUSY) { udelay(10); if (retry_count--) goto again; err = -EIO; dev_err(pd->dev, "Polling timed out\n"); break; } /* handle missing acknowledge and arbitration lost */ if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) { err = -EIO; break; } } deactivate_ch(pd); if (!err) err = num; return err; }