static void twi_chan_cfg(struct sunxi_i2c_platform_data *pdata) { int i; script_item_u item = {0}; script_item_value_type_e type = 0; char twi_para[16] = {0}; for (i=0; i<SUNXI_TWI_NUM; i++) { sprintf(twi_para, "twi%d", i); type = script_get_item(twi_para, "twi_used", &item); if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { I2C_ERR("[twi%d] has no twi_used!\n", i); continue; } if (item.val) twi_used_mask |= SUNXI_TWI_CHAN_MASK(i); type = script_get_item(twi_para, "twi_regulator", &item); if (SCIRPT_ITEM_VALUE_TYPE_STR != type) { I2C_ERR("[twi%d] has no twi_regulator.\n", i); continue; } strncpy(pdata[i].regulator_id, item.str, 16); } }
static int twi_stop(void __iomem *base_addr, int bus_num) { unsigned int timeout = 0xff; twi_set_stop(base_addr); twi_clear_irq_flag(base_addr); twi_get_stop(base_addr);/* it must delay 1 nop to check stop bit */ while(( 1 == twi_get_stop(base_addr))&& (--timeout)); if (timeout == 0) { I2C_ERR("[i2c%d] STOP can't sendout!\n", bus_num); return SUNXI_I2C_TFAIL; } timeout = 0xff; while((TWI_STAT_IDLE != readl(base_addr + TWI_STAT_REG))&&(--timeout)); if (timeout == 0) { I2C_ERR("[i2c%d] i2c state isn't idle(0xf8)\n", bus_num); return SUNXI_I2C_TFAIL; } timeout = 0xff; while((TWI_LCR_IDLE_STATUS != readl(base_addr + TWI_LCR_REG))&&(--timeout)); if (timeout == 0) { I2C_ERR("[i2c%d] i2c lcr isn't idle(0x3a)\n", bus_num); return SUNXI_I2C_TFAIL; } return SUNXI_I2C_OK; }
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; }
INT32 filter_eeprom_read(INT32 eeprom_id, UINT32 offset, UINT32 cnt, UINT8 *buffer) { unsigned end = offset + cnt; int rcode = 0; (void) eeprom_id; int mutex_rcode; /* avoid compiler error */ eeprom_id = 0; if( (offset > CONFIG_SYS_FILTER_EEPROM_SIZE) || (offset + cnt > CONFIG_SYS_FILTER_EEPROM_SIZE) ) { I2C_ERR("%s: out of range offset: 0x%x, count: 0x%x max size: 0x%x\n", __func__, offset, cnt, CONFIG_SYS_FILTER_EEPROM_SIZE); rcode = 1; return rcode; } while( offset < end ) { unsigned len = 0; len = end - offset; #if defined(CONFIG_SYS_I2C_FRAM) len = (len > 128 - offset % 128) ? 128 - offset % 128 : end - offset; #else len = end - offset; #endif mutex_rcode = I2CMUX_MUTEX_LOCK(); if( mutex_rcode != 0 ) { I2C_ERR("%s: Failed to initialize i2c mutex \n", __func__); return 1; } uslSetI2cMux(CONFIG_SYS_I2C_MUX_SF); rcode = i2c_read(CONFIG_SYS_I2C_FILTER_EEPROM_PORT, CONFIG_SYS_I2C_FILTER_EEPROM_ADDR, CONFIG_SYS_I2C_FILTER_EEPROM_ADDR_LEN, offset, len, buffer); uslSetI2cMux(CONFIG_SYS_I2C_MUX_DISCONNECT); I2CMUX_MUTEX_UNLOCK(); if(rcode != 0 ) { I2C_ERR("%s: i2c read from filter eeprom failed - details as follow\n", __func__); I2C_ERR("---------------------------------------------------\n"); I2C_ERR("bus - %d\n", CONFIG_SYS_I2C_FILTER_EEPROM_PORT); I2C_ERR("addr - %d\n", CONFIG_SYS_I2C_FILTER_EEPROM_ADDR); I2C_ERR("addr len - %d\n", CONFIG_SYS_I2C_FILTER_EEPROM_ADDR_LEN); I2C_ERR("offset - %d\n", offset); I2C_ERR("length - %d\n", len); I2C_ERR("---------------------------------------------------\n"); rcode = 1; return rcode; } buffer += len; offset += len; } return rcode; }
static int twi_select_gpio_state(struct pinctrl *pctrl, char *name, u32 no) { int ret = 0; struct pinctrl_state *pctrl_state = NULL; pctrl_state = pinctrl_lookup_state(pctrl, name); if (IS_ERR(pctrl_state)) { I2C_ERR("TWI%d pinctrl_lookup_state(%s) failed! return %p \n", no, name, pctrl_state); return -1; } ret = pinctrl_select_state(pctrl, pctrl_state); if (ret < 0) I2C_ERR("TWI%d pinctrl_select_state(%s) failed! return %d \n", no, name, ret); return ret; }
static int twi_regulator_disable(struct sunxi_i2c_platform_data *pdata) { if (pdata->regulator == NULL) return 0; if (regulator_disable(pdata->regulator) != 0) { I2C_ERR("[i2c%d] enable regulator %s failed!\n", pdata->bus_num, pdata->regulator_id); return -1; } return 0; }
static int twi_restart(void __iomem *base_addr, int bus_num) { unsigned int timeout = 0xff; twi_set_start(base_addr); twi_clear_irq_flag(base_addr); while((1 == twi_get_start(base_addr))&&(--timeout)); if (timeout == 0) { I2C_ERR("[i2c%d] Restart can't sendout!\n", bus_num); return SUNXI_I2C_FAIL; } return SUNXI_I2C_OK; }
static int twi_regulator_request(struct sunxi_i2c_platform_data *pdata) { struct regulator *regu = NULL; /* Consider "n***" as nocare. Support "none", "nocare", "null", "" etc. */ if ((pdata->regulator_id[0] == 'n') || (pdata->regulator_id[0] == 0)) return 0; regu = regulator_get(NULL, pdata->regulator_id); if (IS_ERR(regu)) { I2C_ERR("[i2c%d] get regulator %s failed!\n", pdata->bus_num, pdata->regulator_id); return -1; } pdata->regulator = regu; return 0; }
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; }
/* send 9 clock to release sda */ static int twi_send_clk_9pulse(void __iomem *base_addr, int bus_num) { int twi_scl = 1; int low = 0; int high = 1; int cycle = 0; /* enable scl control */ twi_enable_lcr(base_addr, twi_scl); while (cycle < 9) { if (twi_get_sda(base_addr) && twi_get_sda(base_addr) && twi_get_sda(base_addr)) { break; } /* twi_scl -> low */ twi_set_scl(base_addr, low); udelay(1000); /* twi_scl -> high */ twi_set_scl(base_addr, high); udelay(1000); cycle++; } if (twi_get_sda(base_addr)) { twi_disable_lcr(base_addr, twi_scl); return SUNXI_I2C_OK; } else { I2C_ERR("[i2c%d] SDA is still Stuck Low, failed. \n", bus_num); twi_disable_lcr(base_addr, twi_scl); return SUNXI_I2C_FAIL; } }
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; }