static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) { if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { dev_err(pd->dev, "Unsupported zero length i2c read\n"); return -EIO; } /* Initialize channel registers */ iic_set_clr(pd, ICCR, 0, ICCR_ICE); /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl); iic_wr(pd, ICCH, pd->icch); pd->msg = usr_msg; pd->pos = -1; pd->sr = 0; /* Enable all interrupts to begin with */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); return 0; }
static void sh_mobile_i2c_dma_callback(void *data) { struct sh_mobile_i2c_data *pd = data; sh_mobile_i2c_dma_unmap(pd); pd->pos = pd->msg->len; pd->stop_after_dma = true; iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); }
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; }
static void deactivate_ch(struct sh_mobile_i2c_data *pd) { /* Clear/disable interrupts */ iic_wr(pd, ICSR, 0); iic_wr(pd, ICIC, 0); /* Disable channel */ iic_set_clr(pd, ICCR, 0, ICCR_ICE); /* Disable clock and mark device as idle */ clk_disable(pd->clk); pm_runtime_put_sync(pd->dev); }
/* * 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 void activate_ch(struct sh_mobile_i2c_data *pd) { /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); clk_prepare_enable(pd->clk); /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Mask all interrupts */ iic_wr(pd, ICIC, 0); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); iic_wr(pd, ICCH, pd->icch & 0xff); }
static void activate_ch(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk; u_int32_t num; u_int32_t denom; u_int32_t tmp; /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); clk_enable(pd->clk); /* Get clock rate after clock is enabled */ i2c_clk = clk_get_rate(pd->clk); /* Calculate the value for iccl. From the data sheet: * iccl = (p clock / transfer rate) * (L / (L + H)) * where L and H are the SCL low/high ratio (5/4 in this case). * We also round off the result. */ num = i2c_clk * 5; denom = NORMAL_SPEED * 9; tmp = num * 10 / denom; if (tmp % 10 >= 5) pd->iccl = (u_int8_t)((num/denom) + 1); else pd->iccl = (u_int8_t)(num/denom); /* one more bit of ICCL in ICIC */ if (pd->flags & IIC_FLAG_HAS_ICIC67) { if ((num/denom) > 0xff) pd->icic |= ICIC_ICCLB8; else pd->icic &= ~ICIC_ICCLB8; } /* Calculate the value for icch. From the data sheet: icch = (p clock / transfer rate) * (H / (L + H)) */ num = i2c_clk * 4; tmp = num * 10 / denom; if (tmp % 10 >= 5) pd->icch = (u_int8_t)((num/denom) + 1); else pd->icch = (u_int8_t)(num/denom); /* one more bit of ICCH in ICIC */ if (pd->flags & IIC_FLAG_HAS_ICIC67) { if ((num/denom) > 0xff) pd->icic |= ICIC_ICCHB8; else pd->icic &= ~ICIC_ICCHB8; } /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Mask all interrupts */ iic_wr(pd, ICIC, 0); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl); iic_wr(pd, ICCH, pd->icch); }