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;
}