static int32_t qpnp_iadc_comp_info(void) { struct qpnp_iadc_drv *iadc = qpnp_iadc; int rc = 0; rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id); if (rc < 0) { pr_err("qpnp adc comp id failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision); if (rc < 0) { pr_err("qpnp adc revision read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET, &iadc->iadc_comp.sys_gain); if (rc < 0) pr_err("full scale read failed with %d\n", rc); pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n", iadc->iadc_comp.id, iadc->iadc_comp.revision, iadc->iadc_comp.sys_gain, iadc->iadc_comp.ext_rsense); return rc; }
static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc, int16_t *data) { uint8_t rslt_lsb, rslt_msb; uint16_t rslt; int32_t rc; rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); return rc; } rslt = (rslt_msb << 8) | rslt_lsb; *data = rslt; rc = qpnp_iadc_enable(iadc, false); if (rc) return rc; return 0; }
static int32_t qpnp_iadc_read_conversion_result(int32_t *data) { uint8_t rslt_lsb, rslt_msb; int32_t rc; rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); return rc; } *data = (rslt_msb << 8) | rslt_lsb; rc = qpnp_vadc_check_result(data); if (rc < 0) { pr_err("VADC data check failed\n"); return rc; } return 0; }
static int32_t qpnp_iadc_status_debug(void) { int rc = 0; u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0; rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode); if (rc < 0) { pr_err("mode ctl register read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig); if (rc < 0) { pr_err("digital param read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan); if (rc < 0) { pr_err("channel read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1); if (rc < 0) { pr_err("status1 read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en); if (rc < 0) { pr_err("en read failed with %d\n", rc); return rc; } pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n", status1, dig, chan, mode, en); /* somc workaround for adc lock-up issue for PMIC 3.0 */ if (qpnp_get_pmic_version() == 0x30) qpnp_pon_dvdd_reset(); rc = qpnp_iadc_enable(false); if (rc < 0) { pr_err("IADC disable failed with %d\n", rc); return rc; } return 0; }
static int qpnp_iadc_rds_trim_update_check(struct qpnp_iadc_chip *iadc) { int rc = 0; u8 trim2_val = 0, smbb_batt_trm_data = 0; if (!iadc->rds_trim_default_check) { pr_debug("No internal rds trim check needed\n"); return 0; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &trim2_val); if (rc < 0) { pr_err("qpnp adc trim2_fullscale1 reg read failed %d\n", rc); return rc; } rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave, iadc->batt_id_trim_cnst_rds, &smbb_batt_trm_data, 1); if (rc < 0) { pr_err("batt_id trim_cnst rds reg read failed %d\n", rc); return rc; } pr_debug("n_trim:0x%x smb_trm:0x%x\n", trim2_val, smbb_batt_trm_data); if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEA) { if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) == SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) && (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) { iadc->rsense_workaround_value = QPNP_IADC_RSENSE_DEFAULT_VALUE; iadc->default_internal_rsense = true; } } else if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEB) { if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) >= SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) && (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) { iadc->rsense_workaround_value = QPNP_IADC_RSENSE_DEFAULT_VALUE; iadc->default_internal_rsense = true; } else if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) < SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) && (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) { if (iadc->iadc_comp.id == COMP_ID_GF) { iadc->rsense_workaround_value = QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF; iadc->default_internal_rsense = true; } else if (iadc->iadc_comp.id == COMP_ID_SMIC) { iadc->rsense_workaround_value = QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC; iadc->default_internal_rsense = true; } } } return 0; }
int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense) { uint8_t rslt_rsense; int32_t rc = 0, sign_bit = 0; if (qpnp_iadc_is_valid(iadc) < 0) return -EPROBE_DEFER; if (iadc->external_rsense) { *rsense = iadc->rsense; return rc; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense); if (rc < 0) { pr_err("qpnp adc rsense read failed with %d\n", rc); return rc; } pr_debug("rsense:0%x\n", rslt_rsense); if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK) sign_bit = 1; rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK; if (sign_bit) *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR - (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); else *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR + (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); return rc; }
int32_t qpnp_iadc_get_rsense(int32_t *rsense) { struct qpnp_iadc_drv *iadc = qpnp_iadc; uint8_t rslt_rsense; int32_t rc, sign_bit = 0; if (!iadc || !iadc->iadc_initialized) return -EPROBE_DEFER; if (iadc->external_rsense) *rsense = iadc->rsense; rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense); if (rc < 0) { pr_err("qpnp adc rsense read failed with %d\n", rc); return rc; } pr_debug("rsense:0%x\n", rslt_rsense); if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK) sign_bit = 1; rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK; if (sign_bit) *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR - (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); else *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR + (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); return rc; }
int32_t qpnp_iadc_get_rsense(int32_t *rsense) { uint8_t rslt_rsense; int32_t rc, sign_bit = 0; rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense); if (rc < 0) { pr_err("qpnp adc rsense read failed with %d\n", rc); return rc; } if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK) sign_bit = 1; rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK; if (sign_bit) *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR - (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); else *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR + (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT); return rc; }
static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev) { int rc = 0; u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0; rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode); if (rc < 0) { pr_err("mode ctl register read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig); if (rc < 0) { pr_err("digital param read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan); if (rc < 0) { pr_err("channel read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1); if (rc < 0) { pr_err("status1 read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en); if (rc < 0) { pr_err("en read failed with %d\n", rc); return rc; } pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n", status1, dig, chan, mode, en); rc = qpnp_iadc_enable(dev, false); if (rc < 0) { pr_err("IADC disable failed with %d\n", rc); return rc; } return 0; }
static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc) { int rc = 0; rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id); if (rc < 0) { pr_err("qpnp adc comp id failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &iadc->iadc_comp.revision_dig_major); if (rc < 0) { pr_err("qpnp adc revision2 read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3, &iadc->iadc_comp.revision_ana_minor); if (rc < 0) { pr_err("qpnp adc revision3 read failed with %d\n", rc); return rc; } rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET, &iadc->iadc_comp.sys_gain); if (rc < 0) { pr_err("full scale read failed with %d\n", rc); return rc; } if (iadc->external_rsense) iadc->iadc_comp.ext_rsense = true; pr_debug("fab id = %u, revision_dig_major = %u, revision_ana_minor = %u sys gain = %u, external_rsense = %d\n", iadc->iadc_comp.id, iadc->iadc_comp.revision_dig_major, iadc->iadc_comp.revision_ana_minor, iadc->iadc_comp.sys_gain, iadc->iadc_comp.ext_rsense); return rc; }
static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc) { uint8_t revision; int rc; rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); return rc; } if (revision < QPNP_IADC_SUPPORTED_REVISION2) { pr_err("IADC Version not supported\n"); return -EINVAL; } return 0; }
static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc, enum qpnp_iadc_channels channel, uint16_t *raw_code, uint32_t mode_sel) { u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0; u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0; u8 status1 = 0; uint32_t count = 0; int32_t rc = 0; qpnp_iadc_ch_sel_reg = channel; qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation << QPNP_IADC_DEC_RATIO_SEL; if (iadc->iadc_mode_sel) qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN); else qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN; qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ; rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL, qpnp_iadc_ch_sel_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM, qpnp_iadc_dig_param_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL, iadc->adc->amux_prop->fast_avg_setup); if (rc < 0) { pr_err("qpnp adc fast averaging configure error\n"); return rc; } if (!iadc->iadc_poll_eoc) INIT_COMPLETION(iadc->adc->adc_rslt_completion); rc = qpnp_iadc_enable(iadc, true); if (rc) return rc; rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } if (iadc->iadc_poll_eoc) { while (status1 != QPNP_STATUS1_EOC) { rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK; usleep_range(QPNP_ADC_CONV_TIME_MIN, QPNP_ADC_CONV_TIME_MAX); count++; if (count > QPNP_ADC_ERR_COUNT) { pr_err("retry error exceeded\n"); rc = qpnp_iadc_status_debug(iadc); if (rc < 0) pr_err("IADC status debug failed\n"); rc = -EINVAL; return rc; } } } else { rc = wait_for_completion_timeout( &iadc->adc->adc_rslt_completion, QPNP_ADC_COMPLETION_TIMEOUT); if (!rc) { rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK; if (status1 == QPNP_STATUS1_EOC) pr_debug("End of conversion status set\n"); else { rc = qpnp_iadc_status_debug(iadc); if (rc < 0) { pr_err("status debug failed %d\n", rc); return rc; } return -EINVAL; } } } rc = qpnp_iadc_read_conversion_result(iadc, raw_code); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } return 0; }
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel, uint16_t *raw_code, uint32_t mode_sel) { struct qpnp_iadc_drv *iadc = qpnp_iadc; u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0; u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0; int32_t rc = 0; qpnp_iadc_ch_sel_reg = channel; qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation << QPNP_IADC_DEC_RATIO_SEL; if (iadc->iadc_mode_sel) qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN); else qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN; qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ; rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL, qpnp_iadc_ch_sel_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM, qpnp_iadc_dig_param_reg); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY, iadc->adc->amux_prop->hw_settle_time); if (rc < 0) { pr_err("qpnp adc configure error for hw settling time setup\n"); return rc; } rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL, iadc->adc->amux_prop->fast_avg_setup); if (rc < 0) { pr_err("qpnp adc fast averaging configure error\n"); return rc; } INIT_COMPLETION(iadc->adc->adc_rslt_completion); rc = qpnp_iadc_enable(true); if (rc) return rc; rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion, QPNP_ADC_COMPLETION_TIMEOUT); if (!rc) { u8 status1 = 0; rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1); if (rc < 0) return rc; status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC); if (status1 == QPNP_STATUS1_EOC) pr_debug("End of conversion status set\n"); else { rc = qpnp_iadc_status_debug(); if (rc < 0) { pr_err("status1 read failed with %d\n", rc); return rc; } return -EINVAL; } } rc = qpnp_iadc_read_conversion_result(raw_code); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); return rc; } return 0; }