Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67f9af20 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "hwmon: qpnp-adc: Fix incorrect ADC reads during MPP current sink"

parents c2783991 02b3f658
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ Optional properties:
-qcom,vadc-meas-int-mode : Enable VADC_USR to handle requests to perform recurring measurements
			   for any one supported channel along with supporting single conversion
			   requests.
- qcom,vadc-recalib-check: Add this property to check if recalibration required due to inaccuracy.

Client required property:
- qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ Optional properties:
		0 : Select Timer 1 for a measurement polling interval of 3.9 milliseconds.
		1 : Select Timer 2 for a measurement polling interval of 1 second.
		2 : Select Timer 3 for a measurement polling interval of 4 seconds.
- qcom,adc-tm-recalib-check: Add this property to check if recalibration required due to inaccuracy.

Client required property:
- qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
+188 −113
Original line number Diff line number Diff line
@@ -96,8 +96,8 @@
#define QPNP_VADC_DATA0						0x60
#define QPNP_VADC_DATA1						0x61
#define QPNP_VADC_CONV_TIMEOUT_ERR				2
#define QPNP_VADC_CONV_TIME_MIN					2000
#define QPNP_VADC_CONV_TIME_MAX					2100
#define QPNP_VADC_CONV_TIME_MIN					1000
#define QPNP_VADC_CONV_TIME_MAX					1100
#define QPNP_ADC_COMPLETION_TIMEOUT				HZ
#define QPNP_VADC_ERR_COUNT					20
#define QPNP_OP_MODE_SHIFT					3
@@ -107,6 +107,9 @@
#define QPNP_MIN_TIME						2000
#define QPNP_MAX_TIME						2000
#define QPNP_RETRY						100
#define QPNP_VADC_ABSOLUTE_RECALIB_OFFSET			8
#define QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET			12
#define QPNP_VADC_RECALIB_MAXCNT				10

struct qpnp_vadc_mode_state {
	bool				meas_int_mode;
@@ -128,6 +131,7 @@ struct qpnp_vadc_chip {
	u8				id;
	struct work_struct		trigger_completion_work;
	bool				vadc_poll_eoc;
	bool				vadc_recalib_check;
	u8				revision_ana_minor;
	u8				revision_dig_major;
	struct workqueue_struct		*high_thr_wq;
@@ -198,7 +202,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
	int rc = 0;
	u8 data = 0;

	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS,
						QPNP_VADC_ACCESS_DATA);
	if (rc < 0) {
		pr_err("VADC write access failed\n");
		return rc;
@@ -210,7 +215,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
		return rc;
	}

	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS,
						QPNP_VADC_ACCESS_DATA);
	if (rc < 0) {
		pr_err("VADC write access failed\n");
		return rc;
@@ -1055,14 +1061,19 @@ static void qpnp_vadc_625mv_channel_sel(struct qpnp_vadc_chip *vadc,
	}
}

static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc,
					enum qpnp_adc_calib_type calib_type,
					int *calib_data)
{
	struct qpnp_adc_amux_properties conv;
	int rc, calib_read_1, calib_read_2, count = 0;
	int rc, count = 0, calib_read = 0;
	u8 status1 = 0;
	uint32_t ref_channel_sel = 0;

	if (calib_type == CALIB_ABSOLUTE)
		conv.amux_channel = REF_125V;
	else if (calib_type == CALIB_RATIOMETRIC)
		conv.amux_channel = VDD_VADC;

	conv.decimation = DECIMATION_TYPE2;
	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -1088,26 +1099,43 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
		}
	}

	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
	if (rc) {
		pr_err("qpnp adc read adc failed with %d\n", rc);
		goto calib_fail;
	}
	*calib_data = calib_read;
calib_fail:
	return rc;
}


int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc,
					enum qpnp_adc_calib_type calib_type,
					int *calib_data)
{
	struct qpnp_adc_amux_properties conv;
	int rc, count = 0, calib_read = 0;
	u8 status1 = 0;
	uint32_t ref_channel_sel = 0;

	if (calib_type == CALIB_ABSOLUTE) {
		qpnp_vadc_625mv_channel_sel(vadc, &ref_channel_sel);
		conv.amux_channel = ref_channel_sel;
	} else if (calib_type == CALIB_RATIOMETRIC)
		conv.amux_channel = GND_REF;

	conv.decimation = DECIMATION_TYPE2;
	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;

	rc = qpnp_vadc_configure(vadc, &conv);
	if (rc) {
		pr_err("qpnp adc configure failed with %d\n", rc);
		pr_err("qpnp_vadc configure failed with %d\n", rc);
		goto calib_fail;
	}

	status1 = 0;
	count = 0;
	while (status1 != QPNP_VADC_STATUS1_EOC) {
		rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
		if (rc < 0)
@@ -1122,12 +1150,30 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
		}
	}

	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
	if (rc) {
		pr_err("qpnp adc read adc failed with %d\n", rc);
		goto calib_fail;
	}
	*calib_data = calib_read;
calib_fail:
	return rc;
}

static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
{
	int rc, calib_read_1 = 0, calib_read_2 = 0;

	rc = qpnp_vadc_calib_vref(vadc, CALIB_ABSOLUTE, &calib_read_1);
	if (rc) {
		pr_err("qpnp adc absolute vref calib failed with %d\n", rc);
		goto calib_fail;
	}
	rc = qpnp_vadc_calib_gnd(vadc, CALIB_ABSOLUTE, &calib_read_2);
	if (rc) {
		pr_err("qpnp adc absolute gnd calib failed with %d\n", rc);
		goto calib_fail;
	}
	pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
				calib_read_2, calib_read_1);

@@ -1147,73 +1193,19 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
					calib_read_1;
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
					calib_read_2;
	/* Ratiometric Calibration */
	conv.amux_channel = VDD_VADC;
	conv.decimation = DECIMATION_TYPE2;
	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
	rc = qpnp_vadc_configure(vadc, &conv);
	if (rc) {
		pr_err("qpnp adc configure failed with %d\n", rc);
		goto calib_fail;
	}

	status1 = 0;
	count = 0;
	while (status1 != QPNP_VADC_STATUS1_EOC) {
		rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
		if (rc < 0)
			return rc;
		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
		usleep_range(QPNP_VADC_CONV_TIME_MIN,
					QPNP_VADC_CONV_TIME_MAX);
		count++;
		if (count > QPNP_VADC_ERR_COUNT) {
			rc = -ENODEV;
			goto calib_fail;
		}
	}

	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
	if (rc) {
		pr_err("qpnp adc read adc failed with %d\n", rc);
		goto calib_fail;
	}

	conv.amux_channel = GND_REF;
	conv.decimation = DECIMATION_TYPE2;
	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
	rc = qpnp_vadc_configure(vadc, &conv);
	calib_read_1 = 0;
	calib_read_2 = 0;
	rc = qpnp_vadc_calib_vref(vadc, CALIB_RATIOMETRIC, &calib_read_1);
	if (rc) {
		pr_err("qpnp adc configure failed with %d\n", rc);
		pr_err("qpnp adc ratiometric vref calib failed with %d\n", rc);
		goto calib_fail;
	}

	status1 = 0;
	count = 0;
	while (status1 != QPNP_VADC_STATUS1_EOC) {
		rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
		if (rc < 0)
			return rc;
		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
		usleep_range(QPNP_VADC_CONV_TIME_MIN,
					QPNP_VADC_CONV_TIME_MAX);
		count++;
		if (count > QPNP_VADC_ERR_COUNT) {
			rc = -ENODEV;
			goto calib_fail;
		}
	}

	rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
	rc = qpnp_vadc_calib_gnd(vadc, CALIB_RATIOMETRIC, &calib_read_2);
	if (rc) {
		pr_err("qpnp adc read adc failed with %d\n", rc);
		pr_err("qpnp adc ratiometric gnd calib failed with %d\n", rc);
		goto calib_fail;
	}

	pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
				calib_read_1, calib_read_2);

@@ -1228,10 +1220,10 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
					(calib_read_1 - calib_read_2);
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
					vadc->adc->adc_prop->adc_vdd_reference;
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
					calib_read_1;
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
					calib_read_2;
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref
					= calib_read_1;
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd
					= calib_read_2;

calib_fail:
	return rc;
@@ -1246,6 +1238,7 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
	rc = qpnp_vadc_is_valid(vadc);
	if (rc < 0)
		return rc;
	mutex_lock(&vadc->adc->adc_lock);

	switch (calib_type) {
	case CALIB_RATIOMETRIC:
@@ -1267,10 +1260,11 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
	break;
	default:
		return -EINVAL;
		rc = -EINVAL;
	}

	return 0;
	mutex_unlock(&vadc->adc->adc_lock);
	return rc;
}
EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);

@@ -1415,8 +1409,10 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
					enum qpnp_vadc_channels channel,
					struct qpnp_vadc_result *result)
{
	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
	uint32_t ref_channel, count = 0;
	int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0;
	uint32_t ref_channel, count = 0, local_idx = 0;
	int32_t vref_calib = 0, gnd_calib = 0, new_vref_calib = 0, offset = 0;
	int32_t calib_offset = 0;
	u8 status1 = 0;

	if (qpnp_vadc_is_valid(vadc))
@@ -1427,19 +1423,6 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
	if (vadc->state_copy->vadc_meas_int_enable)
		qpnp_vadc_manage_meas_int_requests(vadc);

	if (!vadc->vadc_init_calib) {
		rc = qpnp_vadc_version_check(vadc);
		if (rc)
			goto fail_unlock;

		rc = qpnp_vadc_calib_device(vadc);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail_unlock;
		} else
			vadc->vadc_init_calib = true;
	}

	if (channel == REF_625MV) {
		qpnp_vadc_625mv_channel_sel(vadc, &ref_channel);
		channel = ref_channel;
@@ -1457,6 +1440,30 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
		goto fail_unlock;
	}

	calib_type = vadc->adc->adc_channels[dt_index].calib_type;
	calib_offset = (calib_type == CALIB_ABSOLUTE) ?
		QPNP_VADC_ABSOLUTE_RECALIB_OFFSET :
		QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET;
	rc = qpnp_vadc_version_check(vadc);
	if (rc)
		goto fail_unlock;
	if (vadc->vadc_recalib_check) {
		rc = qpnp_vadc_calib_vref(vadc, calib_type, &vref_calib);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail_unlock;
		}
	} else if (!vadc->vadc_init_calib) {
		rc = qpnp_vadc_calib_device(vadc);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail_unlock;
		} else {
			vadc->vadc_init_calib = true;
		}
	}

recalibrate:
	vadc->adc->amux_prop->decimation =
			vadc->adc->adc_channels[dt_index].adc_decimation;
	vadc->adc->amux_prop->hw_settle_time =
@@ -1490,6 +1497,8 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
			if (rc < 0)
				goto fail_unlock;
			status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
			if (status1 == QPNP_VADC_STATUS1_EOC)
				break;
			usleep_range(QPNP_VADC_CONV_TIME_MIN,
					QPNP_VADC_CONV_TIME_MAX);
			count++;
@@ -1537,6 +1546,64 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
		goto fail_unlock;
	}

	if (vadc->vadc_recalib_check) {
		rc = qpnp_vadc_calib_gnd(vadc, calib_type, &gnd_calib);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail_unlock;
		}
		rc = qpnp_vadc_calib_vref(vadc, calib_type, &new_vref_calib);
		if (rc < 0) {
			pr_err("qpnp vadc calib read failed with %d\n", rc);
			goto fail_unlock;
		}

		if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) {
			pr_err("invalid recalib count=%d\n", local_idx);
			rc = -EINVAL;
			goto fail_unlock;
		}
		pr_debug(
			"chan=%d, calib=%s, vref_calib=0x%x, gnd_calib=0x%x, new_vref_calib=0x%x\n",
			channel,
			((calib_type == CALIB_ABSOLUTE) ?
			"ABSOLUTE" : "RATIOMETRIC"),
			vref_calib, gnd_calib, new_vref_calib);

		offset = (new_vref_calib - vref_calib);
		if (offset < 0)
			offset = -offset;
		if (offset <= calib_offset) {
			pr_debug(
				"qpnp vadc recalibration not required,offset:%d\n",
								offset);
			local_idx = 0;
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy =
						(vref_calib - gnd_calib);
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx =
			(calib_type == CALIB_ABSOLUTE) ? QPNP_ADC_625_UV :
					vadc->adc->adc_prop->adc_vdd_reference;
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_vref
								= vref_calib;
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd
								= gnd_calib;
		} else {
			offset = 0;
			vref_calib = new_vref_calib;
			local_idx = local_idx + 1;
			if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) {
				pr_err(
				"qpnp_vadc recalibration failed, count=%d",
								local_idx);
			} else {
				pr_debug(
				"qpnp vadc recalibration requested,offset:%d\n",
								offset);
				goto recalibrate;
			}
		}
	}

	amux_prescaling =
		vadc->adc->adc_channels[dt_index].chan_path_prescaling;

@@ -1561,6 +1628,9 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
	vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);

	pr_debug("channel=%d, adc_code=%d adc_result=%lld\n",
			channel, result->adc_code, result->physical);

fail_unlock:
	if (vadc->state_copy->vadc_meas_int_enable)
		qpnp_vadc_manage_meas_int_requests(vadc);
@@ -1618,25 +1688,13 @@ static void qpnp_vadc_unlock(struct qpnp_vadc_chip *vadc)
int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc,
				enum qpnp_vadc_channels channel)
{
	int rc = 0, dt_index = 0;
	int rc = 0, dt_index = 0, calib_type = 0;

	if (qpnp_vadc_is_valid(vadc))
		return -EPROBE_DEFER;

	qpnp_vadc_lock(vadc);

	if (!vadc->vadc_init_calib) {
		rc = qpnp_vadc_version_check(vadc);
		if (rc)
			goto fail;

		rc = qpnp_vadc_calib_device(vadc);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail;
		} else
			vadc->vadc_init_calib = true;
	}

	vadc->adc->amux_prop->amux_channel = channel;

@@ -1650,6 +1708,20 @@ int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc,
		goto fail;
	}

	calib_type = vadc->adc->adc_channels[dt_index].calib_type;
	if (!vadc->vadc_init_calib) {
		rc = qpnp_vadc_version_check(vadc);
		if (rc)
			goto fail;

		rc = qpnp_vadc_calib_device(vadc);
		if (rc) {
			pr_err("Calibration failed\n");
			goto fail;
		} else
			vadc->vadc_init_calib = true;
	}

	vadc->adc->amux_prop->decimation =
			vadc->adc->adc_channels[dt_index].adc_decimation;
	vadc->adc->amux_prop->hw_settle_time =
@@ -2032,6 +2104,9 @@ static int qpnp_vadc_probe(struct spmi_device *spmi)

	INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work);

	vadc->vadc_recalib_check = of_property_read_bool(node,
						"qcom,vadc-recalib-check");

	vadc->vadc_poll_eoc = of_property_read_bool(node,
						"qcom,vadc-poll-eoc");
	if (!vadc->vadc_poll_eoc) {
+213 −2
Original line number Diff line number Diff line
@@ -207,6 +207,7 @@ struct qpnp_adc_tm_chip {
	struct qpnp_adc_drv		*adc;
	struct list_head		list;
	bool				adc_tm_initialized;
	bool				adc_tm_recalib_check;
	int				max_channels_available;
	atomic_t			wq_cnt;
	struct qpnp_vadc_chip		*vadc_dev;
@@ -679,6 +680,62 @@ static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
	return rc;
}

static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
			uint32_t btm_chan)
{
	int rc = 0;
	u8 data_lsb = 0, data_msb = 0;
	uint32_t btm_chan_idx = 0;
	int32_t low_thr = 0, high_thr = 0;

	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
	if (rc < 0) {
		pr_err("Invalid btm channel idx\n");
		return rc;
	}

	rc = qpnp_adc_tm_read_reg(chip,
			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
			&data_lsb);
	if (rc < 0) {
		pr_err("low threshold lsb setting failed\n");
		return rc;
	}

	rc = qpnp_adc_tm_read_reg(chip,
		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
		&data_msb);
	if (rc < 0) {
		pr_err("low threshold msb setting failed\n");
		return rc;
	}

	low_thr = (data_msb << 8) | data_lsb;

	rc = qpnp_adc_tm_read_reg(chip,
		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
		&data_lsb);
	if (rc < 0) {
		pr_err("high threshold lsb setting failed\n");
		return rc;
	}

	rc = qpnp_adc_tm_read_reg(chip,
		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
		&data_msb);
	if (rc < 0) {
		pr_err("high threshold msb setting failed\n");
		return rc;
	}

	high_thr = (data_msb << 8) | data_lsb;

	pr_debug("configured thresholds high:0x%x and low:0x%x\n",
		high_thr, low_thr);

	return rc;
}

static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
{
@@ -1410,10 +1467,148 @@ static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
	return rc;
}

static int qpnp_adc_tm_recalib_request_check(struct qpnp_adc_tm_chip *chip,
			int sensor_num, u8 status_high, u8 *notify_check)
{
	int rc = 0;
	u8 sensor_mask = 0, mode_ctl = 0;
	int32_t old_thr = 0, new_thr = 0;
	uint32_t channel, btm_chan_num, scale_type;
	struct qpnp_vadc_result result;
	struct qpnp_adc_thr_client_info *client_info = NULL;
	struct list_head *thr_list;
	bool status = false;

	if (!chip->adc_tm_recalib_check) {
		*notify_check = 1;
		return rc;
	}

	list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
		client_info = list_entry(thr_list,
				struct qpnp_adc_thr_client_info, list);
		channel = client_info->btm_param->channel;
		btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
		sensor_mask = 1 << sensor_num;

		rc = qpnp_vadc_read(chip->vadc_dev, channel, &result);
		if (rc < 0) {
			pr_err("failure to read vadc channel=%d\n",
					client_info->btm_param->channel);
			goto fail;
		}
		new_thr = result.physical;

		if (status_high)
			old_thr = client_info->btm_param->high_thr;
		else
			old_thr = client_info->btm_param->low_thr;

		if (new_thr > old_thr)
			status = (status_high) ? true : false;
		else
			status = (status_high) ? false : true;

		pr_debug(
			"recalib:sen=%d, new_thr=%d, new_thr_adc_code=0x%x, old_thr=%d status=%d valid_status=%d\n",
			sensor_num, new_thr, result.adc_code,
			old_thr, status_high, status);

		rc = qpnp_adc_tm_read_thr_value(chip, btm_chan_num);
		if (rc < 0) {
			pr_err("adc-tm thresholds read failed\n");
			goto fail;
		}

		if (status) {
			*notify_check = 1;
			pr_debug("Client can be notify\n");
			return rc;
		}

		pr_debug("Client can not be notify, restart measurement\n");
		/* Set measurement in single measurement mode */
		mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
		rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
		if (rc < 0) {
			pr_err("adc-tm single mode select failed\n");
			goto fail;
		}

		/* Disable bank */
		rc = qpnp_adc_tm_disable(chip);
		if (rc < 0) {
			pr_err("adc-tm disable failed\n");
			goto fail;
		}

		/* Check if a conversion is in progress */
		rc = qpnp_adc_tm_req_sts_check(chip);
		if (rc < 0) {
			pr_err("adc-tm req_sts check failed\n");
			goto fail;
		}

		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
							sensor_mask, false);
		if (rc < 0) {
			pr_err("low threshold int write failed\n");
			goto fail;
		}

		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
							sensor_mask, false);
		if (rc < 0) {
			pr_err("high threshold int enable failed\n");
			goto fail;
		}

		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
							sensor_mask, false);
		if (rc < 0) {
			pr_err("multi measurement en failed\n");
			goto fail;
		}

		/* restart measurement */
		scale_type = chip->sensor[sensor_num].scale_type;
		chip->adc->amux_prop->amux_channel = channel;
		chip->adc->amux_prop->decimation =
			chip->adc->adc_channels[sensor_num].adc_decimation;
		chip->adc->amux_prop->hw_settle_time =
			chip->adc->adc_channels[sensor_num].hw_settle_time;
		chip->adc->amux_prop->fast_avg_setup =
			chip->adc->adc_channels[sensor_num].fast_avg_setup;
		chip->adc->amux_prop->mode_sel =
			ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
		adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev,
				client_info->btm_param,
				&chip->adc->amux_prop->chan_prop->low_thr,
				&chip->adc->amux_prop->chan_prop->high_thr);
		qpnp_adc_tm_add_to_list(chip, sensor_num,
				client_info->btm_param,
				chip->adc->amux_prop->chan_prop);
		chip->adc->amux_prop->chan_prop->tm_channel_select =
				chip->sensor[sensor_num].btm_channel_num;
		chip->adc->amux_prop->chan_prop->state_request =
				client_info->btm_param->state_request;

		rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
		if (rc) {
			pr_err("adc-tm configure failed with %d\n", rc);
			goto fail;
		}
		*notify_check = 0;
		pr_debug("BTM channel reconfigured for measuremnt\n");
	}
fail:
	return rc;
}

static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
{
	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0, notify_check = 0;
	u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
	uint32_t btm_chan_num = 0;
@@ -1489,6 +1684,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
				such as usb_id, vbatt, pmic_therm */
			sensor_mask = 1 << sensor_num;
			pr_debug("non thermal node - mask:%x\n", sensor_mask);
			rc = qpnp_adc_tm_recalib_request_check(chip,
					sensor_num, true, &notify_check);
			if (rc < 0 || !notify_check) {
				pr_debug("Calib recheck re-armed rc=%d\n", rc);
				adc_tm_high_enable = 0;
				goto fail;
			}
			rc = qpnp_adc_tm_reg_update(chip,
				QPNP_ADC_TM_HIGH_THR_INT_EN,
				sensor_mask, false);
@@ -1545,6 +1747,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
			/* For non thermal registered clients
				such as usb_id, vbatt, pmic_therm */
			pr_debug("non thermal node - mask:%x\n", sensor_mask);
			rc = qpnp_adc_tm_recalib_request_check(chip,
					sensor_num, false, &notify_check);
			if (rc < 0 || !notify_check) {
				pr_debug("Calib recheck re-armed rc=%d\n", rc);
				adc_tm_low_enable = 0;
				goto fail;
			}
			sensor_mask = 1 << sensor_num;
			rc = qpnp_adc_tm_reg_update(chip,
				QPNP_ADC_TM_LOW_THR_INT_EN,
@@ -1611,7 +1820,7 @@ fail:
	if (adc_tm_high_enable || adc_tm_low_enable)
		queue_work(chip->sensor[sensor_num].req_wq,
				&chip->sensor[sensor_num].work);
	if (rc < 0)
	if (rc < 0 || (!adc_tm_high_enable && !adc_tm_low_enable))
		atomic_dec(&chip->wq_cnt);

	return rc;
@@ -1971,6 +2180,8 @@ static int qpnp_adc_tm_probe(struct spmi_device *spmi)
			pr_err("vadc property missing, rc=%d\n", rc);
		goto fail;
	}
	chip->adc_tm_recalib_check = of_property_read_bool(node,
				"qcom,adc-tm-recalib-check");

	for_each_child_of_node(node, child) {
		char name[25];
+46 −0
Original line number Diff line number Diff line
@@ -150,6 +150,24 @@ struct qpnp_iadc_chip;
/* Structure device for qpnp adc tm */
struct qpnp_adc_tm_chip;

/**
 * enum qpnp_adc_clk_type - Clock rate supported.
 * %CLK_TYPE1: 2P4MHZ
 * %CLK_TYPE2: 4P8MHZ
 * %CLK_TYPE3: 9P6MHZ
 * %CLK_TYPE4: 19P2MHZ
 * %CLK_NONE: Do not use this Clk type.
 *
 * The Clock rate is specific to each channel of the QPNP ADC arbiter.
 */
enum qpnp_adc_clk_type {
	CLK_TYPE1 = 0,
	CLK_TYPE2,
	CLK_TYPE3,
	CLK_TYPE4,
	CLK_NONE,
};

/**
 * enum qpnp_adc_decimation_type - Sampling rate supported.
 * %DECIMATION_TYPE1: 512
@@ -1542,6 +1560,25 @@ int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip,
 * @param:	device instance for the VADC
 */
int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip);
/**
 * qpnp_vadc_calib_vref() - Read calibration channel REF_125V/VDD_VADC
 * @dev:	Structure device for qpnp vadc
 * @calib_type:	absolute or ratiometric calib type.
 * returns calibration channel adc code.
 */
int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc,
				enum qpnp_adc_calib_type calib_type,
				int *calib_data);
/**
 * qpnp_vadc_calib_gnd() - Read calibration channel REF_625MV/GND_REF
 * @dev:	Structure device for qpnp vadc
 * @calib_type:	absolute or ratiometric calib type.
 * returns calibration channel adc code.
 */
int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc,
				enum qpnp_adc_calib_type calib_type,
				int *calib_data);

#else
static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
				uint32_t channel,
@@ -1692,6 +1729,15 @@ static inline int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip,
{ return -ENXIO; }
static inline int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip)
{ return -ENXIO; }
static int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc,
					enum qpnp_adc_calib_type calib_type,
					int *calib_data)
{ return -ENXIO; }
static int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc,
					enum qpnp_adc_calib_type calib_type,
					int *calib_data)
{ return -ENXIO; }

#endif

/* Public API */