static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc, int64_t die_temp) { int64_t temp_var = 0, sys_gain_coeff = 0, old; int32_t coeff_a = 0, coeff_b = 0; int version = 0; version = qpnp_adc_get_revid_version(iadc->dev); if (version == -EINVAL) return 0; old = *result; *result = *result * 1000000; if (iadc->iadc_comp.sys_gain > 127) sys_gain_coeff = -QPNP_COEFF_6 * (iadc->iadc_comp.sys_gain - 128); else sys_gain_coeff = QPNP_COEFF_6 * iadc->iadc_comp.sys_gain; switch (version) { case QPNP_REV_ID_8941_3_1: switch (iadc->iadc_comp.id) { case COMP_ID_GF: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ coeff_a = QPNP_COEFF_2; coeff_b = -QPNP_COEFF_3_TYPEA; } else { if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_5; coeff_b = QPNP_COEFF_6; } else { /* discharge */ coeff_a = -QPNP_COEFF_7; coeff_b = QPNP_COEFF_6; } } break; case COMP_ID_TSMC: default: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ coeff_a = QPNP_COEFF_2; coeff_b = -QPNP_COEFF_3_TYPEB; } else { if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_5; coeff_b = QPNP_COEFF_6; } else { /* discharge */ coeff_a = -QPNP_COEFF_7; coeff_b = QPNP_COEFF_6; } } break; } break; case QPNP_REV_ID_8026_2_1: case QPNP_REV_ID_8026_2_2: /* pm8026 rev 2.1 and 2.2 */ switch (iadc->iadc_comp.id) { case COMP_ID_GF: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { coeff_a = QPNP_COEFF_25; coeff_b = 0; } } else { if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { /* discharge */ coeff_a = 0; coeff_b = 0; } } break; case COMP_ID_TSMC: default: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { coeff_a = QPNP_COEFF_26; coeff_b = 0; } } else { if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { /* discharge */ coeff_a = 0; coeff_b = 0; } } break; } break; case QPNP_REV_ID_8026_1_0: /* pm8026 rev 1.0 */ switch (iadc->iadc_comp.id) { case COMP_ID_GF: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_9; coeff_b = -QPNP_COEFF_17; } else { coeff_a = QPNP_COEFF_10; coeff_b = QPNP_COEFF_18; } } else { if (*result < 0) { /* charge */ coeff_a = -QPNP_COEFF_11; coeff_b = 0; } else { /* discharge */ coeff_a = -QPNP_COEFF_17; coeff_b = -QPNP_COEFF_19; } } break; case COMP_ID_TSMC: default: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_13; coeff_b = -QPNP_COEFF_20; } else { coeff_a = QPNP_COEFF_14; coeff_b = QPNP_COEFF_21; } } else { if (*result < 0) { /* charge */ coeff_a = -QPNP_COEFF_15; coeff_b = 0; } else { /* discharge */ coeff_a = -QPNP_COEFF_12; coeff_b = -QPNP_COEFF_19; } } break; } break; case QPNP_REV_ID_8110_1_0: /* pm8110 rev 1.0 */ switch (iadc->iadc_comp.id) { case COMP_ID_GF: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_24; coeff_b = -QPNP_COEFF_22; } else { coeff_a = QPNP_COEFF_24; coeff_b = -QPNP_COEFF_23; } } break; case COMP_ID_SMIC: default: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = QPNP_COEFF_24; coeff_b = -QPNP_COEFF_22; } else { coeff_a = QPNP_COEFF_24; coeff_b = -QPNP_COEFF_23; } } break; } break; case QPNP_REV_ID_8110_2_0: die_temp -= 25000; /* pm8110 rev 2.0 */ switch (iadc->iadc_comp.id) { case COMP_ID_GF: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { coeff_a = QPNP_COEFF_27; coeff_b = 0; } } break; case COMP_ID_SMIC: default: if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ if (*result < 0) { /* charge */ coeff_a = 0; coeff_b = 0; } else { coeff_a = QPNP_COEFF_28; coeff_b = 0; } } break; } break; default: case QPNP_REV_ID_8026_2_0: /* pm8026 rev 1.0 */ coeff_a = 0; coeff_b = 0; break; } temp_var = (coeff_a * die_temp) + coeff_b; temp_var = div64_s64(temp_var, QPNP_COEFF_4); temp_var = 1000 * (1000000 - temp_var); if (!iadc->iadc_comp.ext_rsense) { /* internal rsense */ *result = div64_s64(*result * 1000, temp_var); } if (iadc->iadc_comp.ext_rsense) { /* external rsense */ sys_gain_coeff = (1000000 + div64_s64(sys_gain_coeff, QPNP_COEFF_4)); temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000); *result = div64_s64(*result * 1000, temp_var); } pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n", old, *result, coeff_a, coeff_b, sys_gain_coeff); return 0; }
int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc, bool batfet_closed) { uint8_t rslt_lsb, rslt_msb; int32_t rc = 0, version = 0; uint16_t raw_data; uint32_t mode_sel = 0; bool iadc_offset_ch_batfet_check; if (qpnp_iadc_is_valid(iadc) < 0) return -EPROBE_DEFER; mutex_lock(&iadc->adc->adc_lock); if (iadc->iadc_poll_eoc) { pr_debug("acquiring iadc eoc wakelock\n"); pm_stay_awake(iadc->dev); } iadc->adc->amux_prop->decimation = DECIMATION_TYPE1; iadc->adc->amux_prop->fast_avg_setup = ADC_FAST_AVG_SAMPLE_1; rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } iadc->adc->calib.gain_raw = raw_data; /* * there is a features on PM8941 in the BMS where if the batfet is * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for * internal rsense. */ version = qpnp_adc_get_revid_version(iadc->dev); if ((version == QPNP_REV_ID_8941_3_1) || (version == QPNP_REV_ID_8941_3_0) || (version == QPNP_REV_ID_8941_2_0)) iadc_offset_ch_batfet_check = true; else iadc_offset_ch_batfet_check = false; if ((iadc_offset_ch_batfet_check && !batfet_closed) || (iadc->external_rsense)) { /* external offset calculation */ rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } } else { /* internal offset calculation */ rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } } iadc->adc->calib.offset_raw = raw_data; if (rc < 0) { pr_err("qpnp adc offset/gain calculation failed\n"); goto fail; } if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2 && iadc->iadc_comp.revision_ana_minor == QPNP_IADC_PM8026_2_REV3) iadc->adc->calib.gain_raw = iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN; pr_debug("raw gain:0x%x, raw offset:0x%x\n", iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw); rc = qpnp_convert_raw_offset_voltage(iadc); if (rc < 0) { pr_err("qpnp raw_voltage conversion failed\n"); goto fail; } rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >> QPNP_BIT_SHIFT_8; rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK; pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb); rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS, QPNP_IADC_SEC_ACCESS_DATA); if (rc < 0) { pr_err("qpnp iadc configure error for sec access\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET, rslt_msb); if (rc < 0) { pr_err("qpnp iadc configure error for MSB write\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS, QPNP_IADC_SEC_ACCESS_DATA); if (rc < 0) { pr_err("qpnp iadc configure error for sec access\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET, rslt_lsb); if (rc < 0) { pr_err("qpnp iadc configure error for LSB write\n"); goto fail; } fail: if (iadc->iadc_poll_eoc) { pr_debug("releasing iadc eoc wakelock\n"); pm_relax(iadc->dev); } mutex_unlock(&iadc->adc->adc_lock); return rc; }
int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc, bool batfet_closed) { uint8_t rslt_lsb, rslt_msb; int32_t rc = 0, version = 0; uint16_t raw_data; uint32_t mode_sel = 0; bool iadc_offset_ch_batfet_check; if (qpnp_iadc_is_valid(iadc) < 0) return -EPROBE_DEFER; mutex_lock(&iadc->adc->adc_lock); if (iadc->iadc_poll_eoc) { pr_debug("acquiring iadc eoc wakelock\n"); pm_stay_awake(iadc->dev); } rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } iadc->adc->calib.gain_raw = raw_data; version = qpnp_adc_get_revid_version(iadc->dev); if ((version == QPNP_REV_ID_8941_3_1) || (version == QPNP_REV_ID_8941_3_0) || (version == QPNP_REV_ID_8941_2_0)) iadc_offset_ch_batfet_check = true; else iadc_offset_ch_batfet_check = false; if ((iadc_offset_ch_batfet_check && !batfet_closed) || (iadc->external_rsense)) { rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } } else { rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2, &raw_data, mode_sel); if (rc < 0) { pr_err("qpnp adc result read failed with %d\n", rc); goto fail; } } iadc->adc->calib.offset_raw = raw_data; if (rc < 0) { pr_err("qpnp adc offset/gain calculation failed\n"); goto fail; } if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2 && iadc->iadc_comp.revision_ana_minor == QPNP_IADC_PM8026_2_REV3) iadc->adc->calib.gain_raw = iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN; pr_debug("raw gain:0x%x, raw offset:0x%x\n", iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw); rc = qpnp_convert_raw_offset_voltage(iadc); if (rc < 0) { pr_err("qpnp raw_voltage conversion failed\n"); goto fail; } rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >> QPNP_BIT_SHIFT_8; rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK; pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb); rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS, QPNP_IADC_SEC_ACCESS_DATA); if (rc < 0) { pr_err("qpnp iadc configure error for sec access\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET, rslt_msb); if (rc < 0) { pr_err("qpnp iadc configure error for MSB write\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS, QPNP_IADC_SEC_ACCESS_DATA); if (rc < 0) { pr_err("qpnp iadc configure error for sec access\n"); goto fail; } rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET, rslt_lsb); if (rc < 0) { pr_err("qpnp iadc configure error for LSB write\n"); goto fail; } fail: if (iadc->iadc_poll_eoc) { pr_debug("releasing iadc eoc wakelock\n"); pm_relax(iadc->dev); } mutex_unlock(&iadc->adc->adc_lock); return rc; }