static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op, unsigned char data) { unsigned char ret = 0; unsigned long flags; dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data); spin_lock_irqsave(&pd->lock, flags); switch (op) { case OP_START: /* issue start and trigger DTE interrupt */ iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; case OP_TX_FIRST: /* disable DTE interrupt and write data */ iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE); iic_wr(pd, ICDR, data); break; case OP_TX: /* write data */ iic_wr(pd, ICDR, data); break; case OP_TX_STOP: /* write data and issue a stop afterwards */ iic_wr(pd, ICDR, data); iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; case OP_TX_TO_RX: /* select read mode */ iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); break; case OP_RX: /* just read data */ ret = iic_rd(pd, ICDR); break; case OP_RX_STOP: /* enable DTE interrupt, issue stop */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); break; case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); ret = iic_rd(pd, ICDR); iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); break; } spin_unlock_irqrestore(&pd->lock, flags); dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret); return ret; }
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 = iic_rd(pd, ICSR); 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 */ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); 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 */ iic_wr(pd, ICSR, sr & ~ICSR_WAIT); if (wakeup) { pd->sr |= SW_DONE; wake_up(&pd->wait); } return IRQ_HANDLED; }
static int poll_busy(struct sh_mobile_i2c_data *pd) { int i; for (i = 1000; i; i--) { u_int8_t val = iic_rd(pd, ICSR); 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)) { /* handle missing acknowledge and arbitration lost */ val |= pd->sr; if (val & ICSR_TACK) return -ENXIO; if (val & ICSR_AL) return -EAGAIN; break; } udelay(10); } return i ? 0 : -ETIMEDOUT; }
//8 bits register address only static int read_eeprom(U8 slvAddr, U8 addr, U8 *pBuf) { int i; U8 ch[2]; ch[1] = addr; rIICDS = slvAddr; rIICSTAT = 0xf0; //MasTx,Start for(i=0; i<2; i++) if(iic_wr(ch[i], i)) break; if(i<2) { rIICSTAT = 0xd0; //Stop MasTx condition return -1; } rIICDS = slvAddr; rIICSTAT = 0xb0; //Master Rx,Start if(!iic_wr(0, 0)) //wait ack i = iic_rd(pBuf); rIICSTAT = 0x90; //Stop MaxRx condition return i; }
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) { struct sh_mobile_i2c_data *pd = dev_id; unsigned char sr; int wakeup = 0; sr = iic_rd(pd, ICSR); 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); /* Kick off TxDMA after preface was done */ if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0) iic_set_clr(pd, ICIC, ICIC_TDMAE, 0); else if (sr & (ICSR_AL | ICSR_TACK)) /* don't interrupt transaction - continue to issue stop */ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); else if (pd->msg->flags & I2C_M_RD) wakeup = sh_mobile_i2c_isr_rx(pd); else wakeup = sh_mobile_i2c_isr_tx(pd); /* Kick off RxDMA after preface was done */ if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1) iic_set_clr(pd, ICIC, ICIC_RDMAE, 0); if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ iic_wr(pd, ICSR, sr & ~ICSR_WAIT); if (wakeup) { pd->sr |= SW_DONE; wake_up(&pd->wait); } /* defeat write posting to avoid spurious WAIT interrupts */ iic_rd(pd, ICSR); return IRQ_HANDLED; }
/* * r8a7740 chip has lasting errata on I2C I/O pad reset. * this is work-around for it. */ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) { iic_set_clr(pd, ICCR, ICCR_ICE, 0); iic_rd(pd, ICCR); /* dummy read */ iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0); iic_rd(pd, ICSTART); /* dummy read */ udelay(10); iic_wr(pd, ICCR, ICCR_SCP); iic_wr(pd, ICSTART, 0); udelay(10); iic_wr(pd, ICCR, ICCR_TRS); udelay(10); iic_wr(pd, ICCR, 0); udelay(10); iic_wr(pd, ICCR, ICCR_TRS); udelay(10); return sh_mobile_i2c_init(pd); }
static int poll_dte(struct sh_mobile_i2c_data *pd) { int i; for (i = 1000; i; i--) { u_int8_t val = iic_rd(pd, ICSR); if (val & ICSR_DTE) break; if (val & ICSR_TACK) return -ENXIO; udelay(10); } return i ? 0 : -ETIMEDOUT; }
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 = iic_rd(pd, ICSR); 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; }
static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, unsigned char set, unsigned char clr) { iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); }