static int twi_request_gpio(struct sunxi_i2c *i2c) { int ret = 0; I2C_DBG("Pinctrl init %d ... [%s]\n", i2c->bus_num, i2c->adap.dev.parent->init_name); if (!twi_chan_is_enable(i2c->bus_num)) return -1; i2c->pctrl = devm_pinctrl_get(i2c->adap.dev.parent); if (IS_ERR(i2c->pctrl)) { I2C_ERR("TWI%d devm_pinctrl_get() failed! return %ld\n", i2c->bus_num, PTR_ERR(i2c->pctrl)); return -1; } i2c->pctrl_state = pinctrl_lookup_state(i2c->pctrl, PINCTRL_STATE_DEFAULT); if (IS_ERR(i2c->pctrl_state)) { I2C_ERR("TWI%d pinctrl_lookup_state() failed! return %p \n", i2c->bus_num, i2c->pctrl_state); return -1; } ret = pinctrl_select_state(i2c->pctrl, i2c->pctrl_state); if (ret < 0) I2C_ERR("TWI%d pinctrl_select_state() failed! return %d \n", i2c->bus_num, ret); return ret; }
/* set twi clock * * clk_n: clock divider factor n * clk_m: clock divider factor m */ static inline void twi_clk_write_reg(unsigned int clk_n, unsigned int clk_m, void __iomem *base_addr) { unsigned int reg_val = readl(base_addr + TWI_CLK_REG); I2C_DBG("%s: clk_n = %d, clk_m = %d\n", __FUNCTION__, clk_n, clk_m); reg_val &= ~(TWI_CLK_DIV_M | TWI_CLK_DIV_N); reg_val |= ( clk_n |(clk_m << 3) ); writel(reg_val, base_addr + TWI_CLK_REG); }
//struct mutex msm_i2c_rw_mutex; int msm_i2c_write(int chip, void *buf, size_t count) { int rc = ERR_NOT_READY; if (!dev.pdata) { I2C_DBG(ALWAYS, "[MSM-I2C]: %s: called when driver is not installed\n", __func__); return rc; } struct i2c_msg msg[] = { {.addr = chip, .flags = 0, .len = count, .buf = buf,} };
static int msm_i2c_poll_notbusy(int warn) { uint32_t retries = 0; while (retries != 200) { uint32_t status = readl(dev.pdata->i2c_base + I2C_STATUS); if (!(status & I2C_STATUS_BUS_ACTIVE)) { if (retries && warn){ I2C_DBG(DEBUGLEVEL, "Warning bus was busy (%d)\n", retries); return 0; } } if (retries++ > 100) mdelay(10); } I2C_ERR("Error waiting for notbusy\n"); return ERR_TIMED_OUT; }
static void msm_i2c_interrupt_locked(void) { uint32_t status = readl(dev.pdata->i2c_base + I2C_STATUS); bool not_done = true; #if DEBUG_I2C dump_status(status); #endif if (!dev.msg) { I2C_DBG(DEBUGLEVEL, "IRQ but nothing to do!, status %x\n", status); return; } if (status & I2C_STATUS_ERROR_MASK) goto out_err; if (!(status & I2C_STATUS_WR_BUFFER_FULL)) not_done = msm_i2c_fill_write_buffer(); if (status & I2C_STATUS_RD_BUFFER_FULL) msm_i2c_read_buffer(); if (dev.pos >= 0 && dev.cnt == 0) { if (dev.rem > 1) { dev.rem--; dev.msg++; dev.pos = -1; dev.cnt = dev.msg->len; } else if (!not_done && !dev.need_flush) { timeout = 0; return; } } return; out_err: I2C_ERR("error, status %x\n", status); dev.ret = ERROR; timeout = ERR_TIMED_OUT; }
static void dump_status(uint32_t status) { I2C_DBG(DEBUGLEVEL, "STATUS (0x%.8x): ", status); if (status & I2C_STATUS_BUS_MASTER) I2C_DBG(DEBUGLEVEL, "MST "); if (status & I2C_STATUS_BUS_ACTIVE) I2C_DBG(DEBUGLEVEL, "ACT "); if (status & I2C_STATUS_INVALID_WRITE) I2C_DBG(DEBUGLEVEL, "INV_WR "); if (status & I2C_STATUS_ARB_LOST) I2C_DBG(DEBUGLEVEL, "ARB_LST "); if (status & I2C_STATUS_PACKET_NACKED) I2C_DBG(DEBUGLEVEL, "NAK "); if (status & I2C_STATUS_BUS_ERROR) I2C_DBG(DEBUGLEVEL, "BUS_ERR "); if (status & I2C_STATUS_RD_BUFFER_FULL) I2C_DBG(DEBUGLEVEL, "RD_FULL "); if (status & I2C_STATUS_WR_BUFFER_FULL) I2C_DBG(DEBUGLEVEL, "WR_FULL "); if (status & I2C_STATUS_FAILED) I2C_DBG(DEBUGLEVEL, "FAIL 0x%x", (status & I2C_STATUS_FAILED)); I2C_DBG(DEBUGLEVEL, "\n"); }
int msm_i2c_xfer(struct i2c_msg msgs[], int num) { int ret, ret_wait; clk_enable(dev.pdata->clk_nr); unmask_interrupt(dev.pdata->irq_nr); ret = msm_i2c_poll_notbusy(1); if (ret) { ret = msm_i2c_recover_bus_busy(); if (ret) goto err; } enter_critical_section(); if (dev.flush_cnt) { I2C_DBG(DEBUGLEVEL, "%d unrequested bytes read\n", dev.flush_cnt); } dev.msg = msgs; dev.rem = num; dev.pos = -1; dev.ret = num; dev.need_flush = false; dev.flush_cnt = 0; dev.cnt = msgs->len; msm_i2c_interrupt_locked(); exit_critical_section(); /* * Now that we've setup the xfer, the ISR will transfer the data * and wake us up with dev.err set if there was an error */ ret_wait = msm_i2c_poll_notbusy(0); /* Read may not have stopped in time */ enter_critical_section(); if (dev.flush_cnt) { I2C_DBG(DEBUGLEVEL, "%d unrequested bytes read\n", dev.flush_cnt); } ret = dev.ret; dev.msg = NULL; dev.rem = 0; dev.pos = 0; dev.ret = 0; dev.flush_cnt = 0; dev.cnt = 0; exit_critical_section(); if (ret_wait) { I2C_DBG(DEBUGLEVEL, "Still busy after xfer completion\n"); ret_wait = msm_i2c_recover_bus_busy(); if (ret_wait) goto err; } if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = ERR_TIMED_OUT; } if (ret < 0) { I2C_ERR("Error during data xfer (%d)\n", ret); msm_i2c_recover_bus_busy(); } /* if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = 2; msm_i2c_recover_bus_busy(); } if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = ERR_TIMED_OUT; } if (ret < 0) { I2C_ERR("Error during data xfer (%d)\n", ret); msm_i2c_recover_bus_busy(); } */ err: mask_interrupt(dev.pdata->irq_nr); clk_disable(dev.pdata->clk_nr); return ret; }
static int msm_i2c_recover_bus_busy(void) { int i; bool gpio_clk_status = false; uint32_t status = readl(dev.pdata->i2c_base + I2C_STATUS); I2C_DBG_FUNC_LINE(); if (!(status & (I2C_STATUS_BUS_ACTIVE | I2C_STATUS_WR_BUFFER_FULL))) return 0; if (dev.pdata->set_mux_to_i2c) dev.pdata->set_mux_to_i2c(0); if (status & I2C_STATUS_RD_BUFFER_FULL) { I2C_DBG(DEBUGLEVEL, "Read buffer full, status %x, intf %x\n", status, readl(dev.pdata->i2c_base + I2C_INTERFACE_SELECT)); writel(I2C_WRITE_DATA_LAST_BYTE, dev.pdata->i2c_base + I2C_WRITE_DATA); readl(dev.pdata->i2c_base + I2C_READ_DATA); } else if (status & I2C_STATUS_BUS_MASTER) { I2C_DBG(DEBUGLEVEL, "Still the bus master, status %x, intf %x\n", status, readl(dev.pdata->i2c_base + I2C_INTERFACE_SELECT)); writel(I2C_WRITE_DATA_LAST_BYTE | 0xff, dev.pdata->i2c_base + I2C_WRITE_DATA); } I2C_DBG(DEBUGLEVEL, "i2c_scl: %d, i2c_sda: %d\n", gpio_get(dev.pdata->scl_gpio), gpio_get(dev.pdata->sda_gpio)); for (i = 0; i < 9; i++) { if (gpio_get(dev.pdata->sda_gpio) && gpio_clk_status) break; gpio_set(dev.pdata->scl_gpio, 0); udelay(5); gpio_set(dev.pdata->sda_gpio, 0); udelay(5); gpio_config(dev.pdata->scl_gpio, GPIO_INPUT); udelay(5); if (!gpio_get(dev.pdata->scl_gpio)) udelay(20); if (!gpio_get(dev.pdata->scl_gpio)) mdelay(10); gpio_clk_status = gpio_get(dev.pdata->scl_gpio); gpio_config(dev.pdata->sda_gpio, GPIO_INPUT); udelay(5); } if (dev.pdata->set_mux_to_i2c) dev.pdata->set_mux_to_i2c(1); udelay(10); status = readl(dev.pdata->i2c_base + I2C_STATUS); if (!(status & I2C_STATUS_BUS_ACTIVE)) { I2C_DBG(DEBUGLEVEL, "Bus busy cleared after %d clock cycles, status %x, intf %x\n", i, status, readl(dev.pdata->i2c_base + I2C_INTERFACE_SELECT)); return 0; } I2C_DBG(DEBUGLEVEL, "Bus still busy, status %x, intf %x\n", status, readl(dev.pdata->i2c_base + I2C_INTERFACE_SELECT)); return ERR_NOT_READY; }