static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; unsigned int offset; u32 mask, val; if (i2c_dev->hw->has_mst_fifo) { mask = I2C_MST_FIFO_CONTROL_TX_FLUSH | I2C_MST_FIFO_CONTROL_RX_FLUSH; offset = I2C_MST_FIFO_CONTROL; } else { mask = I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; offset = I2C_FIFO_CONTROL; } val = i2c_readl(i2c_dev, offset); val |= mask; i2c_writel(i2c_dev, val, offset); while (i2c_readl(i2c_dev, offset) & mask) { if (time_after(jiffies, timeout)) { dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); return -ETIMEDOUT; } msleep(1); } return 0; }
static void i2c_jz_reset(struct i2c_jz *i2c) { i2c_readl(i2c, I2C_CTXABRT); i2c_readl(i2c, I2C_INTST); i2c_jz_disable(i2c); udelay(10); i2c_jz_enable(i2c); }
static int i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int msg_num) { int ret, i; unsigned long stat; struct lpc2k_i2c *i2c = adap->algo_data; /* Check for bus idle condition */ stat = i2c_readl(i2c->reg_base + LPC24XX_I2STAT); if (stat != m_i2c_idle) { /* Something is holding the bus, try to clear it */ ret = i2c_lpc2k_clear_arb(i2c); if (ret) { dev_err(&i2c->adap.dev, "Bus is not idle\n"); return ret; } } dev_dbg(&i2c->adap.dev, "Processing total messages = %d\n", msg_num); /* Process a single message at a time */ for (i = 0; i < msg_num; i++) { /* Save message pointer and current message data index */ i2c->msg = &msgs[i]; i2c->msg_idx = 0; i2c->msg_status = -EBUSY; i2c->is_last = (i == (msg_num - 1)); ret = lpc2k_process_msg(i2c, i); if (ret) return ret; } return msg_num; }
static inline void rk30_i2c_clean_stop(struct rk30_i2c *i2c) { unsigned int con = i2c_readl(i2c->regs + I2C_CON); con &= ~I2C_CON_STOP; i2c_writel(con, i2c->regs + I2C_CON); }
static irqreturn_t rk30_i2c_irq(int irq, void *dev_id) { struct rk30_i2c *i2c = dev_id; unsigned int ipd; spin_lock(&i2c->lock); ipd = i2c_readl(i2c->regs + I2C_IPD); if(i2c->state == STATE_IDLE){ dev_info(i2c->dev, "Addr[0x%02x] irq in STATE_IDLE, ipd = 0x%x\n", i2c->addr, ipd); i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD); goto out; } #if defined(CONFIG_MFD_TRS65910) //for trs65910 Trsilicon peter if(ipd & I2C_NAKRCVIPD && i2c->addr == 0x2d){ i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); goto out; }else if(ipd & I2C_NAKRCVIPD){ i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); i2c->error = -EAGAIN; goto out; } #else if(ipd & I2C_NAKRCVIPD){ i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); i2c->error = -EAGAIN; goto out; } #endif rk30_i2c_irq_nextblock(i2c, ipd); out: spin_unlock(&i2c->lock); return IRQ_HANDLED; }
static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) { u32 int_mask; int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask; i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); }
static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) { if (time_after(jiffies, timeout)) { dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); return -ETIMEDOUT; } msleep(1); } return 0; }
static inline void rk30_i2c_send_stop(struct rk30_i2c *i2c) { unsigned int con = i2c_readl(i2c->regs + I2C_CON); con |= I2C_CON_STOP; if(con & I2C_CON_START) dev_warn(i2c->dev, "I2C_CON: start bit is set\n"); i2c_writel(con, i2c->regs + I2C_CON); }
static inline void rk30_set_rx_mode(struct rk30_i2c *i2c, unsigned int lastnak) { unsigned long con = i2c_readl(i2c->regs + I2C_CON); con &= (~I2C_CON_MASK); con |= (I2C_CON_MOD_RX << 1); if(lastnak) con |= I2C_CON_LASTACK; i2c_writel(con, i2c->regs + I2C_CON); }
static int i2c_disable_clk(struct i2c_jz *i2c) { int timeout = 10; int tmp = i2c_readl(i2c, I2C_STA); while ((tmp & I2C_STA_MSTACT) && (--timeout > 0)) { udelay(90); tmp = i2c_readl(i2c, I2C_STA); } if (timeout > 0) { clk_disable(i2c->clk); return 0; } else { dev_err(&(i2c->adap.dev), "--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp); i2c_jz_reset(i2c); clk_disable(i2c->clk); return -ETIMEDOUT; } }
static irqreturn_t i2c_lpc2k_handler(int this_irq, void *dev_id) { struct lpc2k_i2c *i2c = (struct lpc2k_i2c *) dev_id; if (i2c_readl(i2c->reg_base + LPC24XX_I2CONSET) & LPC24XX_SI) { i2c_lpc2k_pump_msg(i2c); return IRQ_HANDLED; } else { return IRQ_NONE; } }
static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) { u32 val; int rx_fifo_avail; u8 *buf = i2c_dev->msg_buf; size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; if (i2c_dev->hw->has_mst_fifo) { val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >> I2C_MST_FIFO_STATUS_RX_SHIFT; } else {
static int i2c_jz_disable(struct i2c_jz *i2c) { int timeout = TIMEOUT; i2c_writel(i2c, I2C_ENB, 0); while ((i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0)) msleep(1); if (timeout) return 0; printk("enable i2c%d failed\n", i2c->adap.nr); return -ETIMEDOUT; }
static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) { u32 val; int rx_fifo_avail; int word; u8 *buf = i2c_dev->msg_buf; size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> I2C_FIFO_STATUS_RX_SHIFT; words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; if (words_to_transfer > rx_fifo_avail) words_to_transfer = rx_fifo_avail; for (word = 0; word < words_to_transfer; word++) { val = i2c_readl(i2c_dev, I2C_RX_FIFO); put_unaligned_le32(val, buf); buf += BYTES_PER_FIFO_WORD; buf_remaining -= BYTES_PER_FIFO_WORD; rx_fifo_avail--; } if (rx_fifo_avail > 0 && buf_remaining > 0) { int bytes_to_transfer = buf_remaining; int byte; BUG_ON(bytes_to_transfer > 3); val = i2c_readl(i2c_dev, I2C_RX_FIFO); for (byte = 0; byte < bytes_to_transfer; byte++) { *buf++ = val & 0xFF; val >>= 8; } buf_remaining -= bytes_to_transfer; rx_fifo_avail--; }
static void rk30_irq_read_get_data(struct rk30_i2c *i2c) { unsigned int i, len = i2c->msg->len - i2c->msg_ptr; unsigned int p; len = (len >= 32)?32:len; for(i = 0; i < len; i++) { if(i%4 == 0) p = i2c_readl(i2c->regs + I2C_RXDATA_BASE + (i/4) * 4); i2c->msg->buf[i2c->msg_ptr++] = (p >>((i%4) * 8)) & 0xff; } return; }
static int i2c_lpc2k_clear_arb(struct lpc2k_i2c *i2c) { long timeout = jiffies + HZ; int ret = 0; /* * If the transfer needs to abort for some reason, we'll try to * force a stop condition to clear any pending bus conditions */ i2c_writel(LPC24XX_STO, i2c->reg_base + LPC24XX_I2CONSET); /* Wait for status change */ while (jiffies < timeout && (i2c_readl(i2c->reg_base + LPC24XX_I2STAT) != m_i2c_idle)) cpu_relax(); if (i2c_readl(i2c->reg_base + LPC24XX_I2STAT) != m_i2c_idle) { /* Bus was not idle, try to reset adapter */ i2c_lpc2k_reset(i2c); ret = -EBUSY; } return ret; }
/* SCL Divisor = 8 * (CLKDIVL + CLKDIVH) * SCL = i2c_rate/ SCLK Divisor */ static void rk30_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate) { unsigned long i2c_rate = clk_get_rate(i2c->clk); unsigned int div, divl, divh; if((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate)) return; i2c->i2c_rate = i2c_rate; i2c->scl_rate = scl_rate; div = rk30_ceil(i2c_rate, scl_rate * 8); divh = divl = rk30_ceil(div, 2); i2c_writel(I2C_CLKDIV_VAL(divl, divh), i2c->regs + I2C_CLKDIV); i2c_dbg(i2c->dev, "set clk(I2C_CLKDIV: 0x%08x)\n", i2c_readl(i2c->regs + I2C_CLKDIV)); return; }
void isp1301_update(struct reg_list *list) { for (; list && list->name; list++) { //TRACE_MSG1(TCD, "list: %s", list->name); memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32)); switch(list->size) { case 1: list->values[0] = i2c_readb(list->reg); break; case 2: list->values[0] = i2c_readw(list->reg); break; case 4: list->values[0] = i2c_readl(list->reg); break; } } }
static irqreturn_t rk30_i2c_irq(int irq, void *dev_id) { struct rk30_i2c *i2c = dev_id; unsigned int ipd; spin_lock(&i2c->lock); ipd = i2c_readl(i2c->regs + I2C_IPD); if(i2c->state == STATE_IDLE) { dev_info(i2c->dev, "Addr[0x%02x] irq in STATE_IDLE, ipd = 0x%x\n", i2c->addr, ipd); i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD); goto out; } if(ipd & I2C_NAKRCVIPD) { i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); i2c->error = -EAGAIN; goto out; } rk30_i2c_irq_nextblock(i2c, ipd); out: spin_unlock(&i2c->lock); return IRQ_HANDLED; }
/* function: send read command * return: 0, successful * 1, txfifo valid entry is more than receive fifo, before send read command, * must be read. * 2, txfifo count is 0 or rxfifo count is 0. * */ static inline unsigned int i2c_send_rcmd(struct i2c_jz *i2c) { unsigned int tx_count, rx_count, count, tx_valid, rx_valid; tx_valid = i2c_readl(i2c, I2C_TXFLR); rx_valid = i2c_readl(i2c, I2C_RXFLR); tx_count = I2C_FIFO_LEN - tx_valid; rx_count = I2C_FIFO_LEN - rx_valid; #ifdef CONFIG_I2C_DEBUG_INFO if(i2c->debug > DEBUG_INFO) dev_info(&(i2c->adap.dev), "%s, tx_valid = %d, rx_valid = %d," " tx_count = %d, rx_count = %d\n", __func__, tx_valid, rx_valid, tx_count, rx_count); #endif if (tx_valid > rx_count) { dev_warn(&(i2c->adap.dev), "\n\n###Warrning: I2C transfer fifo valid entry is more receive fifo, " "before send read cmd, please read data from " "the read fifo.\n\n"); return 1; } if (!tx_count || !rx_count) { dev_warn(&(i2c->adap.dev), "\n\n###Warrning: I2C receive fifo or transfer fifo is full, " "before send read cmd, please read data from " "the read fifo or wait some time.\n\n"); return 2; } count = min3(i2c->rd_len, tx_count, rx_count); #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_INFO) dev_info(&(i2c->adap.dev), "%s, Before send read cmd, " "need_send = %d, left_send = %d\n", __func__, count ,i2c->rd_len); #endif i2c->rd_len -= count; if (!i2c->rd_len) { while (count > 1) { i2c_writel(i2c, I2C_DC, I2C_DC_READ); count--; } if (i2c->r_end_type == MSG_END_STOP) { i2c_writel(i2c, I2C_DC, I2C_DC_READ | I2C_DC_STP); } else { i2c_writel(i2c, I2C_DC, I2C_DC_READ); } } else { while (count > 0) { i2c_writel(i2c, I2C_DC, I2C_DC_READ); count--; } } #ifdef CONFIG_I2C_DEBUG_INFO if(i2c->debug > DEBUG_INFO) dev_info(&(i2c->adap.dev), "%s, After send read cmd, " "left_send = %d\n", __func__, i2c->rd_len); #endif return 0; }
static irqreturn_t i2c_jz_irq(int irqno, void *dev_id) { unsigned short tmp, intst, intmsk; struct i2c_jz *i2c = dev_id; intst = i2c_readl(i2c, I2C_INTST); intmsk = i2c_readl(i2c, I2C_INTM); #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_INFO) dev_info(&(i2c->adap.dev), "--I2C irq register INTST:0x%08x\n", intst); #endif if ((intst & I2C_INTST_TXABT) && (intmsk & I2C_INTM_MTXABT)) { dev_err(&(i2c->adap.dev), "%s %d, I2C transfer error, ABORT interrupt\n", __func__, __LINE__); goto END_TRSF_IRQ_HND; } if ((intst & I2C_INTST_ISTP) && (intmsk & I2C_INTM_MISTP)) { i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_INFO) { dev_info(&(i2c->adap.dev), "%s, Now stop condition has occurred," "and left data length is %d\n", __func__, i2c->len); } #endif if (i2c->len == 0) goto END_TRSF_IRQ_HND; } if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP)) { if (!i2c->len) { if (i2c->w_end_type == MSG_END_REPEAT_START) { goto END_TRSF_IRQ_HND; } else { tmp = i2c_readl(i2c, I2C_INTM); tmp &= ~I2C_INTM_MTXEMP; i2c_writel(i2c, I2C_INTM, tmp); } } else { while ((i2c->len > 0) && (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF)) { tmp = *i2c->wbuf++; if (i2c->len == 1) { if (i2c->w_end_type == MSG_END_STOP) tmp |= I2C_DC_STP; } i2c_writel(i2c, I2C_DC, tmp); i2c->len -= 1; } if (i2c->len == 0) { i2c_writel(i2c, I2C_TXTL, 0); } } } if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) { #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug >= DEBUG_INFO) { dev_info(&(i2c->adap.dev), "%s, Before read I2C_DC, " "left_send_cmd = %d, left_read_cnt = %d," " rx_valid = %d, tx_valid = %d\n", __func__, i2c->rd_len, i2c->len, i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); } #endif while ((i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) && (i2c->len > 0)) { tmp = i2c_readl(i2c, I2C_DC) & 0xff; *i2c->rbuf++ = tmp; i2c->len--; } #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug >= DEBUG_INFO) dev_info(&(i2c->adap.dev), "%s, After read I2C_DC, " "left_read_cnt = %d," " rx_valid = %d, tx_valid = %d\n", __func__, i2c->len, i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); #endif if (i2c->len == 0) { goto END_RECE_IRQ_HND; } if (i2c->len <= I2C_FIFO_LEN) { i2c_writel(i2c, I2C_RXTL, i2c->len - 1); } if (i2c_send_rcmd(i2c)) { dev_err(&(i2c->adap.dev), "%s %d, I2C controller has BUG," " RXFLR or TXFLR can not clear\n", __func__, __LINE__); BUG(); } #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_INFO) dev_info(&(i2c->adap.dev), "%s, After send read command, " "left_send_cmd = %d, " "left_read_cnt = %d\n", __func__, i2c->rd_len, i2c->len); #endif } if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) { dev_err(&(i2c->adap.dev), "%s %d, I2C transfer error, RXFIFO over full\n", __func__, __LINE__); i2c_readl(i2c, I2C_CRXOF); /* clear RXOF bit */ } if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) { dev_err(&(i2c->adap.dev), "%s %d, I2C transfer error, TXFIFO over full\n", __func__, __LINE__); i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ goto END_TRSF_IRQ_HND; } return IRQ_HANDLED; END_RECE_IRQ_HND: END_TRSF_IRQ_HND: i2c_writel(i2c, I2C_INTM, 0); complete(&i2c->complete); return IRQ_HANDLED; }
static inline int xfer_read(struct i2c_jz *i2c, unsigned char *buf, int len, enum msg_end_type end_type) { int ret = 0; long timeout; unsigned short tmp; unsigned int wait_complete_timeout_ms; wait_complete_timeout_ms = len * 1000 * 9 * 2 / i2c->rate + CONFIG_I2C_JZV10_WAIT_MS; #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_WARN) dev_info(&(i2c->adap.dev), "%s, Begin read msg, want to read length is %d\n", __func__, len); #endif memset(buf, 0, len); i2c->rd_len = len; i2c->len = len; i2c->rbuf = buf; i2c->r_end_type = end_type; i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ if (len <= I2C_FIFO_LEN) { i2c_writel(i2c, I2C_RXTL, len - 1); } else { i2c_writel(i2c, I2C_RXTL, RX_LEVEL); } while (i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) { i2c_readl(i2c, I2C_DC); } if (i2c_send_rcmd(i2c)) BUG(); tmp = I2C_INTM_MRXFL | I2C_INTM_MTXABT; if (end_type == MSG_END_STOP) tmp |= I2C_INTM_MISTP; i2c_writel(i2c, I2C_INTM, tmp); timeout = wait_for_completion_timeout(&i2c->complete, msecs_to_jiffies (wait_complete_timeout_ms)); if (!timeout) { dev_err(&(i2c->adap.dev), "--I2C irq read timeout\n"); #ifdef I2C_DEBUG i2c_jz_dump_regs(i2c); #endif ret = -ETIMEDOUT; } tmp = i2c_readl(i2c, I2C_TXABRT); if (tmp) { txabrt(i2c, tmp); if (tmp > 0x1 && tmp < 0x10) ret = -ENXIO; else ret = -EIO; // ABRT_GCALL_READ if (tmp & (1 << 5)) { ret = -EAGAIN; } i2c_readl(i2c, I2C_CTXABRT); } if (ret < 0) i2c_jz_reset(i2c); #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_WARN) dev_info(&(i2c->adap.dev), "%s, Reading msg over\n", __func__); #endif return ret; }
static inline int xfer_write(struct i2c_jz *i2c, unsigned char *buf, int len, enum msg_end_type end_type) { int ret = 0; long timeout = TIMEOUT; unsigned short reg_tmp; unsigned int wait_complete_timeout_ms; wait_complete_timeout_ms = len * 1000 * 9 * 2 / i2c->rate + CONFIG_I2C_JZV10_WAIT_MS; #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_WARN) dev_info(&(i2c->adap.dev), "%s, Begin write msg, want to write length is %d\n", __func__, len); #endif i2c->wbuf = buf; i2c->len = len; i2c_writel(i2c, I2C_TXTL, TX_LEVEL); i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ i2c->w_end_type = end_type; while ((i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF) && (i2c->len > 0)) { reg_tmp = *i2c->wbuf++; if (i2c->len == 1) { if (end_type == MSG_END_STOP) { reg_tmp |= I2C_DC_STP; } } i2c_writel(i2c, I2C_DC, reg_tmp); i2c->len -= 1; } if (i2c->len == 0) { i2c_writel(i2c, I2C_TXTL, 0); } reg_tmp = I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF; if (end_type == MSG_END_STOP) reg_tmp |= I2C_INTM_MISTP; i2c_writel(i2c, I2C_INTM, reg_tmp); timeout = wait_for_completion_timeout(&i2c->complete, msecs_to_jiffies (wait_complete_timeout_ms)); if (!timeout) { dev_err(&(i2c->adap.dev), "--I2C pio write wait timeout\n"); #ifdef I2C_DEBUG i2c_jz_dump_regs(i2c); #endif ret = -ETIMEDOUT; } reg_tmp = i2c_readl(i2c, I2C_TXABRT); if (reg_tmp) { txabrt(i2c, reg_tmp); if (reg_tmp > 0x1 && reg_tmp < 0x10) ret = -ENXIO; else ret = -EIO; //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend if (reg_tmp & 8) { ret = -EAGAIN; } i2c_readl(i2c, I2C_CTXABRT); } if (ret < 0) i2c_jz_reset(i2c); #ifdef CONFIG_I2C_DEBUG_INFO if (i2c->debug > DEBUG_WARN) dev_info(&(i2c->adap.dev), "%s, Write msg over\n", __func__); #endif return ret; }
static int i2c_jz_probe(struct platform_device *dev) { int ret = 0; struct i2c_jz *i2c; struct resource *res; unsigned int reg_tmp; i2c = kzalloc(sizeof(struct i2c_jz), GFP_KERNEL); if (!i2c) { printk("Error: Now we can not malloc memory for I2C!\n"); ret = -ENOMEM; goto ERR0; } i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &i2c_jz_algorithm; i2c->adap.retries = 5; i2c->adap.timeout = 5; i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; i2c->adap.nr = dev->id; sprintf(i2c->adap.name, "i2c%u", dev->id); i2c->clk = clk_get(&dev->dev, i2c->adap.name); if (!i2c->clk) { printk("Error: Now we can not get i2c%d clock!\n", dev->id); ret = -ENODEV; goto clk_failed; } res = platform_get_resource(dev, IORESOURCE_MEM, 0); i2c->iomem = ioremap(res->start, resource_size(res)); if (!i2c->iomem) { printk("Error: Now we can remap IO for I2C%d!\n", dev->id); ret = -ENOMEM; goto io_failed; } i2c->irq = platform_get_irq(dev, 0); ret = request_irq(i2c->irq, i2c_jz_irq, IRQF_DISABLED, dev_name(&dev->dev), i2c); if (ret) { printk("Error: Now we can request irq for I2C%d!\n", dev->id); ret = -ENODEV; goto irq_failed; } clk_enable(i2c->clk); res = platform_get_resource(dev, IORESOURCE_BUS, 0); i2c_set_speed(i2c, res->start * 1000); #if 0 reg_tmp = i2c_readl(i2c, I2C_DC); reg_tmp &= ~I2C_DC_STP; i2c_writel(i2c, I2C_DC, reg_tmp); #endif reg_tmp = i2c_readl(i2c, I2C_CTRL); reg_tmp |= I2C_CTRL_REST; i2c_writel(i2c, I2C_CTRL, reg_tmp); // for jgao WHY? // i2c_writel(i2c, I2C_FLT, 0xF); /*set filter*/ i2c_writel(i2c, I2C_INTM, 0x0); init_completion(&i2c->complete); ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&(i2c->adap.dev), KERN_INFO "I2C: Failed to add bus\n"); goto adapt_failed; } platform_set_drvdata(dev, i2c); i2c_jz_enable(i2c); clk_disable(i2c->clk); #ifdef CONFIG_I2C_DEBUG_INFO ret = create_debug_sysfs_interface(&dev->dev); if (ret < 0) dev_err(&i2c->adap.dev, "create debug sysfs interface failed\n"); #endif return 0; adapt_failed: free_irq(i2c->irq, i2c); irq_failed: iounmap(i2c->iomem); io_failed: clk_put(i2c->clk); clk_failed: kfree(i2c); ERR0: return ret; }
/* rk30_i2c_doxfer * * this starts an i2c transfer */ static int rk30_i2c_doxfer(struct rk30_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned long timeout, flags; int error = 0; /* 32 -- max transfer bytes * 2 -- addr bytes * 2 * 3 -- max reg addr bytes * 9 -- cycles per bytes * max cycles: (32 + 2 + 3) * 9 --> 400 cycles */ int msleep_time = 400 * 1000/ i2c->scl_rate; // ms if (i2c->suspended) { dev_err(i2c->dev, "i2c is suspended\n"); return -EIO; } spin_lock_irqsave(&i2c->lock, flags); if(rk30_i2c_set_master(i2c, msgs, num) < 0) { spin_unlock_irqrestore(&i2c->lock, flags); dev_err(i2c->dev, "addr[0x%02x] set master error\n", msgs[0].addr); return -EIO; } i2c->addr = msgs[0].addr; i2c->msg_ptr = 0; i2c->error = 0; i2c->is_busy = 1; i2c->state = STATE_START; i2c->complete_what = 0; i2c_writel(I2C_STARTIEN, i2c->regs + I2C_IEN); spin_unlock_irqrestore(&i2c->lock, flags); rk30_i2c_enable(i2c, (i2c->count > 32)?0:1); //if count > 32, byte(32) send ack if (in_atomic()) { int tmo = I2C_WAIT_TIMEOUT * USEC_PER_MSEC; while(tmo-- && i2c->is_busy != 0) udelay(1); timeout = (tmo <= 0)?0:1; } else timeout = wait_event_timeout(i2c->wait, (i2c->is_busy == 0), msecs_to_jiffies(I2C_WAIT_TIMEOUT)); spin_lock_irqsave(&i2c->lock, flags); i2c->state = STATE_IDLE; error = i2c->error; spin_unlock_irqrestore(&i2c->lock, flags); if (timeout == 0) { if(error < 0) i2c_dbg(i2c->dev, "error = %d\n", error); else if((i2c->complete_what !=COMPLETE_READ && i2c->complete_what != COMPLETE_WRITE)) { dev_err(i2c->dev, "Addr[0x%02x] wait event timeout, state: %d, is_busy: %d, error: %d, complete_what: 0x%x, ipd: 0x%x\n", msgs[0].addr, i2c->state, i2c->is_busy, error, i2c->complete_what, i2c_readl(i2c->regs + I2C_IPD)); //rk30_show_regs(i2c); error = -ETIMEDOUT; msleep(msleep_time); rk30_i2c_send_stop(i2c); msleep(1); } else i2c_dbg(i2c->dev, "Addr[0x%02x] wait event timeout, but transfer complete\n", i2c->addr); } i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD); rk30_i2c_disable_irq(i2c); rk30_i2c_disable(i2c); if(error == -EAGAIN) i2c_dbg(i2c->dev, "No ack(complete_what: 0x%x), Maybe slave(addr: 0x%02x) not exist or abnormal power-on\n", i2c->complete_what, i2c->addr); return error; }
static void rk30_show_regs(struct rk30_i2c *i2c) { int i; dev_info(i2c->dev, "i2c->clk = %lu\n", clk_get_rate(i2c->clk)); dev_info(i2c->dev, "i2c->start = %d\n", i2c->state); dev_info(i2c->dev, "I2C_CON: 0x%08x\n", i2c_readl(i2c->regs + I2C_CON)); dev_info(i2c->dev, "I2C_CLKDIV: 0x%08x\n", i2c_readl(i2c->regs + I2C_CLKDIV)); dev_info(i2c->dev, "I2C_MRXADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXADDR)); dev_info(i2c->dev, "I2C_MRXRADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXRADDR)); dev_info(i2c->dev, "I2C_MTXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MTXCNT)); dev_info(i2c->dev, "I2C_MRXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXCNT)); dev_info(i2c->dev, "I2C_IEN: 0x%08x\n", i2c_readl(i2c->regs + I2C_IEN)); dev_info(i2c->dev, "I2C_IPD: 0x%08x\n", i2c_readl(i2c->regs + I2C_IPD)); dev_info(i2c->dev, "I2C_FCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_FCNT)); for( i = 0; i < 8; i ++) dev_info(i2c->dev, "I2C_TXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_TXDATA_BASE + i * 4)); for( i = 0; i < 8; i ++) dev_info(i2c->dev, "I2C_RXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4)); }
static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) { unsigned long status; unsigned char data; /* * I2C in the LPC2xxx series is basically a state machine. * Just run through the steps based on the current status. */ status = i2c_readl(i2c->reg_base + LPC24XX_I2STAT); switch (status) { case m_start: case m_repstart: /* Start bit was just sent out, send out addr and dir */ data = (i2c->msg->addr << 1); if (i2c->msg->flags & I2C_M_RD) data |= 1; i2c_writel((unsigned long) data, i2c->reg_base + LPC24XX_I2DAT); i2c_writel(LPC24XX_STA, i2c->reg_base + LPC24XX_I2CONCLR); dev_dbg(&i2c->adap.dev, "Start sent, sending address " "0x%02x\n", data); break; case mx_addr_w_ack: case mx_data_w_ack: /* * Address or data was sent out with an ACK. If there is more * data to send, send it now */ if (i2c->msg_idx < i2c->msg->len) { i2c_writel((unsigned long) i2c->msg->buf[i2c->msg_idx], i2c->reg_base + LPC24XX_I2DAT); dev_dbg(&i2c->adap.dev, "ACK ok, sending " "(0x%02x)\n", i2c->msg->buf[i2c->msg_idx]); } else if (i2c->is_last) { /* Last message, send stop */ i2c_writel(LPC24XX_STO | LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONSET); i2c_writel(LPC24XX_SI, i2c->reg_base + LPC24XX_I2CONCLR); i2c->msg_status = 0; dev_dbg(&i2c->adap.dev, "ACK ok, sending stop\n"); disable_irq_nosync(i2c->irq); } else { i2c->msg_status = 0; dev_dbg(&i2c->adap.dev, "ACK ok, idling until " "next message start\n"); disable_irq_nosync(i2c->irq); } i2c->msg_idx++; break; case mr_addr_r_ack: /* * Receive first byte from slave */ if (i2c->msg->len == 1) { /* Last byte, return NACK */ i2c_writel(LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONCLR); } else { /* Not last byte, return ACK */ i2c_writel(LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONSET); } i2c_writel(LPC24XX_STA, i2c->reg_base + LPC24XX_I2CONCLR); break; case mr_data_r_nack: /* * The I2C shows NACK status on reads, so we need to accept * the NACK as an ACK here. This should be ok, as the real * BACK would of been caught on the address write. */ case mr_data_r_ack: /* * Data was received */ if (i2c->msg_idx < i2c->msg->len) { i2c->msg->buf[i2c->msg_idx] = i2c_readl(i2c->reg_base + LPC24XX_I2DAT); dev_dbg(&i2c->adap.dev, "ACK ok, received " "(0x%02x)\n", i2c->msg->buf[i2c->msg_idx]); } /* * If transfer is done, send STOP */ if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) { i2c_writel(LPC24XX_STO | LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONSET); i2c_writel(LPC24XX_SI, i2c->reg_base + LPC24XX_I2CONCLR); i2c->msg_status = 0; dev_dbg(&i2c->adap.dev, "ACK ok, sending stop\n"); } /* * Message is done */ if (i2c->msg_idx >= i2c->msg->len - 1) { i2c->msg_status = 0; dev_dbg(&i2c->adap.dev, "ACK ok, idling until " "next message start\n"); disable_irq_nosync(i2c->irq); } /* * One pre-last data input, send NACK to tell the slave that * this is going to be the last data byte to be transferred. */ if (i2c->msg_idx >= i2c->msg->len - 2) { /* One byte left to receive - NACK */ i2c_writel(LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONCLR); } else { /* More than one byte left to receive - ACK */ i2c_writel(LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONSET); } i2c_writel(LPC24XX_STA, i2c->reg_base + LPC24XX_I2CONCLR); i2c->msg_idx++; break; case mx_addr_w_nack: case mx_data_w_nack: case mr_addr_r_nack: /* * NACK! Processing is done */ i2c_writel(LPC24XX_STO | LPC24XX_AA, i2c->reg_base + LPC24XX_I2CONSET); i2c->msg_status = -ENODEV; dev_dbg(&i2c->adap.dev, "Device NACKed, error\n"); disable_irq_nosync(i2c->irq); break; case m_data_arb_lost: /* * Arbitration lost */ i2c->msg_status = -EIO; dev_dbg(&i2c->adap.dev, "Arbitration lost, error\n"); /* * Release the I2C bus */ i2c_writel(LPC24XX_STA | LPC24XX_STO, i2c->reg_base + LPC24XX_I2CONCLR); disable_irq_nosync(i2c->irq); break; default: /* Unexpected statuses */ i2c->msg_status = -EIO; dev_err(&i2c->adap.dev, "Unexpected status, error (%x)\n", (unsigned int) status); disable_irq_nosync(i2c->irq); break; } /* Exit on failure or all bytes transferred */ if (i2c->msg_status != -EBUSY) wake_up(&i2c->wait); /* * If `msg_status` is zero, then `lpc2k_process_msg()` is responsible * for clearing the SI flag. */ if (i2c->msg_status != 0) i2c_writel(LPC24XX_SI, i2c->reg_base + LPC24XX_I2CONCLR); }