static int32_t qpnp_iadc_configure_interrupt(void)
{
	int rc = 0;
	u8 data = 0;

	/* Configure interrupt as an Edge trigger */
	rc = qpnp_iadc_write_reg(QPNP_INT_SET_TYPE,
					QPNP_INT_CLR_MASK);
	if (rc < 0) {
		pr_err("%s Interrupt configure failed\n", __func__);
		return rc;
	}

	/* Configure interrupt for rising edge trigger */
	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_HIGH,
					QPNP_INT_CLR_MASK);
	if (rc < 0) {
		pr_err("%s Rising edge trigger configure failed\n", __func__);
		return rc;
	}

	/* Disable low level interrupt triggering */
	data = QPNP_INT_CLR_MASK;
	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_LOW,
					(~data & QPNP_INT_CLR_MASK));
	if (rc < 0) {
		pr_err("%s Setting level low to disable failed\n", __func__);
		return rc;
	}

	return 0;
}
static void trigger_iadc_completion(struct work_struct *work)
{
	struct qpnp_iadc_drv *iadc = qpnp_iadc;
	int rc;

	rc = qpnp_iadc_write_reg(QPNP_INT_CLR, QPNP_INT_CLR_MASK);
	if (rc < 0)
		pr_err("qpnp iadc interrupt mask failed with %d\n", rc);

	complete(&iadc->adc->adc_rslt_completion);

	return;
}
static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
{
    int rc = 0;
    u8 data = 0;

    data = QPNP_IADC_ADC_EN;
    if (state) {
        rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
                                 data);
        if (rc < 0) {
            pr_err("IADC enable failed\n");
            return rc;
        }
    } else {
        rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
                                 (~data & QPNP_IADC_ADC_EN));
        if (rc < 0) {
            pr_err("IADC disable failed\n");
            return rc;
        }
    }

    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;
}
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;
}
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;
}
int32_t qpnp_iadc_calibrate_for_trim(void)
{
	struct qpnp_iadc_drv *iadc = qpnp_iadc;
	uint8_t rslt_lsb, rslt_msb;
	int32_t rc = 0;
	uint16_t raw_data;
	uint32_t mode_sel = 0;

	if (!iadc || !iadc->iadc_initialized)
		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);
	}

	/* Exported symbol may be called from outside this driver.
	 * Ensure this driver is ready (probed) before supporting
	 * calibration.
	 */
	rc = qpnp_iadc_is_ready();
	if (rc < 0)
		goto fail;

	rc = qpnp_iadc_configure(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;

	if (iadc->external_rsense) {
		/* external offset calculation */
		rc = qpnp_iadc_configure(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(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;
	}

	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();
	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(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(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(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(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;
}
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
						int32_t *result)
{
	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_mode_reg |= (QPNP_IADC_USE_BMS_DATA | QPNP_IADC_USE_BMS_DATA
			| QPNP_IADC_OFFSET_RMV_EN | QPNP_IADC_ADC_TRIM_EN);

	qpnp_iadc_ch_sel_reg = channel << QPNP_IADC_ADC_CHX_SEL_SHIFT;

	qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
					QPNP_IADC_DEC_RATIO_SEL;

	qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;

	rc = qpnp_iadc_write_reg(QPNP_INT_EN_SET,
					QPNP_INT_EN_SET_EOC_INT_EN_SET);
	if (rc < 0) {
		pr_err("qpnp adc configure error for interrupt setup\n");
		return rc;
	}

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

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

	wait_for_completion(&iadc->adc->adc_rslt_completion);

	rc = qpnp_iadc_read_conversion_result(result);
	if (rc) {
		pr_err("qpnp adc read adc failed with %d\n", rc);
		return rc;
	}

	return 0;
}
Example #9
0
int32_t qpnp_iadc_calibrate_for_trim(void)
{
	struct qpnp_iadc_drv *iadc = qpnp_iadc;
	uint8_t rslt_lsb, rslt_msb;
	int32_t rc = 0;
	uint16_t raw_data;
	uint32_t mode_sel = 0;

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

	rc = qpnp_iadc_configure(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;
	}

	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();
	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(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(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(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(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;
}
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;
}
static int32_t qpnp_iadc_calibrate_for_trim(void)
{
	struct qpnp_iadc_drv *iadc = qpnp_iadc;
	uint8_t rslt_lsb, rslt_msb;
	int32_t rc = 0;
	uint16_t raw_data;
	uint32_t mode_sel = 0;

	rc = qpnp_iadc_configure(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;

	rc = qpnp_iadc_configure(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;
	}

	rc = qpnp_convert_raw_offset_voltage();

	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;

	rc = qpnp_iadc_write_reg(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(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(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(QPNP_IADC_LSB_OFFSET,
						rslt_lsb);
	if (rc < 0) {
		pr_err("qpnp iadc configure error for LSB write\n");
		goto fail;
	}
fail:
	return rc;
}