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