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

Commit b1b5d0af authored by Siddartha Mohanadoss's avatar Siddartha Mohanadoss
Browse files

thermal: qpnp-adc-tm: Update reverse threshold and notification



Add support to scale reverse thresholds on VADC_TM refresh
peripheral for voltage measurements such as vbatt, vph_pwr,
thermistor channels, PMIC die temperature.

VADC_TM refresh uses one interrupt for high and low threshold
notification. Update the sequence to check the respective
sensors status for high/low threshold crossing for the VADC_TM
refresh and notify the clients on a threshold crossing.

Change-Id: I070b537e14b505bc247f2f5e6a0e125f1d0fbb81
Signed-off-by: default avatarSiddartha Mohanadoss <smohanad@codeaurora.org>
parent d1313a37
Loading
Loading
Loading
Loading
+151 −119
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#define PMI_CHG_SCALE_1		-138890
#define PMI_CHG_SCALE_2		391750000000
#define QPNP_VADC_HC_VREF_CODE		0x4000
#define QPNP_VADC_HC_VDD_REFERENCE_MV	1875

/* Units for temperature below (on x axis) is in 0.1DegC as
   required by the battery driver. Note the resolution used
@@ -789,14 +790,24 @@ int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(struct qpnp_vadc_chip *chip,
	int64_t low_output = 0, high_output = 0;
	int rc = 0, sign = 0;

	rc = qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_ABSOLUTE);
	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
	low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
	high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;

	if (param->adc_tm_hc) {
		low_output *= QPNP_VADC_HC_VREF_CODE;
		do_div(low_output, (QPNP_VADC_HC_VDD_REFERENCE_MV * 1000));
		high_output *= QPNP_VADC_HC_VREF_CODE;
		do_div(high_output, (QPNP_VADC_HC_VDD_REFERENCE_MV * 1000));
	} else {
		rc = qpnp_get_vadc_gain_and_offset(chip, &btm_param,
							CALIB_ABSOLUTE);
		if (rc < 0) {
		pr_err("Could not acquire gain and offset\n");
		return rc;
		}

	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
	low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
		/* Convert to voltage threshold */
		low_output = (low_output - QPNP_ADC_625_UV) * btm_param.dy;
		if (low_output < 0) {
@@ -809,8 +820,6 @@ int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(struct qpnp_vadc_chip *chip,
		low_output += btm_param.adc_gnd;

		sign = 0;
	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
	high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
		/* Convert to voltage threshold */
		high_output = (high_output - QPNP_ADC_625_UV) * btm_param.dy;
		if (high_output < 0) {
@@ -821,9 +830,11 @@ int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(struct qpnp_vadc_chip *chip,
		if (sign)
			high_output = -high_output;
		high_output += btm_param.adc_gnd;
	}

	*low_threshold = (uint32_t) low_output;
	*high_threshold = (uint32_t) high_output;

	pr_debug("high_temp:%d, low_temp:%d\n", param->high_temp,
				param->low_temp);
	pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
@@ -1079,8 +1090,18 @@ int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,
{
	int64_t adc_voltage = 0;
	struct qpnp_vadc_linear_graph param1;
	int negative_offset;
	int negative_offset = 0;

	if (adc_properties->adc_hc) {
		/* (ADC code * vref_vadc (1.875V)) / 0x4000 */
		adc_voltage = (int64_t) reg;
		adc_voltage *= QPNP_VADC_HC_VDD_REFERENCE_MV;
		adc_voltage = div64_s64(adc_voltage,
					QPNP_VADC_HC_VREF_CODE);
		qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
			ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
			adc_voltage, result);
	} else {
		qpnp_get_vadc_gain_and_offset(chip, &param1, CALIB_RATIOMETRIC);

		adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
@@ -1091,17 +1112,12 @@ int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,

		do_div(adc_voltage, param1.dy);

	if (adc_properties->adc_hc)
		qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
			ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
			adc_voltage, result);
	else
		qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
			ARRAY_SIZE(adcmap_100k_104ef_104fb),
			adc_voltage, result);

		if (negative_offset)
			adc_voltage = -adc_voltage;
	}

	return 0;
}
@@ -1114,8 +1130,6 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
	struct qpnp_vadc_linear_graph param1;
	int rc;

	qpnp_get_vadc_gain_and_offset(chip, &param1, CALIB_RATIOMETRIC);

	if (adc_properties->adc_hc) {
		rc = qpnp_adc_map_temp_voltage(
			adcmap_100k_104ef_104fb_1875_vref,
@@ -1123,13 +1137,25 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
			param->low_thr_temp, &param->low_thr_voltage);
		if (rc)
			return rc;
		param->low_thr_voltage *= QPNP_VADC_HC_VREF_CODE;
		do_div(param->low_thr_voltage, QPNP_VADC_HC_VDD_REFERENCE_MV);

		rc = qpnp_adc_map_temp_voltage(
			adcmap_100k_104ef_104fb_1875_vref,
			ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
			param->high_thr_temp, &param->high_thr_voltage);
		if (rc)
			return rc;
		param->high_thr_voltage *= QPNP_VADC_HC_VREF_CODE;
		do_div(param->high_thr_voltage, QPNP_VADC_HC_VDD_REFERENCE_MV);
	} else {
		qpnp_get_vadc_gain_and_offset(chip, &param1, CALIB_RATIOMETRIC);

		rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
			ARRAY_SIZE(adcmap_100k_104ef_104fb),
			param->low_thr_temp, &param->low_thr_voltage);
		if (rc)
			return rc;
	}

		param->low_thr_voltage *= param1.dy;
		do_div(param->low_thr_voltage, param1.adc_vref);
@@ -1144,6 +1170,7 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
		param->high_thr_voltage *= param1.dy;
		do_div(param->high_thr_voltage, param1.adc_vref);
		param->high_thr_voltage += param1.adc_gnd;
	}

	return 0;
}
@@ -1251,7 +1278,7 @@ int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *chip,
}
EXPORT_SYMBOL(qpnp_adc_usb_scaler);

int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *chip,
int32_t qpnp_adc_absolute_rthr(struct qpnp_vadc_chip *chip,
		struct qpnp_adc_tm_btm_param *param,
		uint32_t *low_threshold, uint32_t *high_threshold)
{
@@ -1259,32 +1286,49 @@ int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *chip,
	int rc = 0, sign = 0;
	int64_t low_thr = 0, high_thr = 0;

	rc = qpnp_get_vadc_gain_and_offset(chip, &vbatt_param, CALIB_ABSOLUTE);
	if (param->adc_tm_hc) {
		low_thr = (param->low_thr/param->gain_den);
		low_thr *= param->gain_num;
		low_thr *= QPNP_VADC_HC_VREF_CODE;
		do_div(low_thr, (QPNP_VADC_HC_VDD_REFERENCE_MV * 1000));
		*low_threshold = low_thr;

		high_thr = (param->high_thr/param->gain_den);
		high_thr *= param->gain_num;
		high_thr *= QPNP_VADC_HC_VREF_CODE;
		do_div(high_thr, (QPNP_VADC_HC_VDD_REFERENCE_MV * 1000));
		*high_threshold = high_thr;
	} else {
		rc = qpnp_get_vadc_gain_and_offset(chip, &vbatt_param,
							CALIB_ABSOLUTE);
		if (rc < 0)
			return rc;

	low_thr = (((param->low_thr/param->gain_den) - QPNP_ADC_625_UV) *
				vbatt_param.dy);
		low_thr = (((param->low_thr/param->gain_den) -
				QPNP_ADC_625_UV) * vbatt_param.dy);
		if (low_thr < 0) {
			sign = 1;
			low_thr = -low_thr;
		}
		low_thr = low_thr * param->gain_num;
		do_div(low_thr, QPNP_ADC_625_UV);
		if (sign)
			low_thr = -low_thr;
		*low_threshold = low_thr + vbatt_param.adc_gnd;

		sign = 0;
	high_thr = (((param->high_thr/param->gain_den) - QPNP_ADC_625_UV) *
				vbatt_param.dy);
		high_thr = (((param->high_thr/param->gain_den) -
				QPNP_ADC_625_UV) * vbatt_param.dy);
		if (high_thr < 0) {
			sign = 1;
			high_thr = -high_thr;
		}
		high_thr = high_thr * param->gain_num;
		do_div(high_thr, QPNP_ADC_625_UV);
		if (sign)
			high_thr = -high_thr;
		*high_threshold = high_thr + vbatt_param.adc_gnd;
	}

	pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
				param->low_thr);
@@ -1292,48 +1336,16 @@ int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *chip,
				*low_threshold);
	return 0;
}
EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
EXPORT_SYMBOL(qpnp_adc_absolute_rthr);

int32_t qpnp_adc_absolute_rthr(struct qpnp_vadc_chip *chip,
int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *chip,
		struct qpnp_adc_tm_btm_param *param,
		uint32_t *low_threshold, uint32_t *high_threshold)
{
	struct qpnp_vadc_linear_graph vbatt_param;
	int rc = 0, sign = 0;
	int64_t low_thr = 0, high_thr = 0;

	rc = qpnp_get_vadc_gain_and_offset(chip, &vbatt_param, CALIB_ABSOLUTE);
	if (rc < 0)
		return rc;

	low_thr = (((param->low_thr) - QPNP_ADC_625_UV) * vbatt_param.dy);
	if (low_thr < 0) {
		sign = 1;
		low_thr = -low_thr;
	}
	do_div(low_thr, QPNP_ADC_625_UV);
	if (sign)
		low_thr = -low_thr;
	*low_threshold = low_thr + vbatt_param.adc_gnd;

	sign = 0;
	high_thr = (((param->high_thr) - QPNP_ADC_625_UV) * vbatt_param.dy);
	if (high_thr < 0) {
		sign = 1;
		high_thr = -high_thr;
	}
	do_div(high_thr, QPNP_ADC_625_UV);
	if (sign)
		high_thr = -high_thr;
	*high_threshold = high_thr + vbatt_param.adc_gnd;

	pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
				param->low_thr);
	pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
				*low_threshold);
	return 0;
	return qpnp_adc_absolute_rthr(chip, param, low_threshold,
							high_threshold);
}
EXPORT_SYMBOL(qpnp_adc_absolute_rthr);
EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);

int32_t qpnp_vadc_absolute_rthr(struct qpnp_vadc_chip *chip,
		const struct qpnp_vadc_chan_properties *chan_prop,
@@ -1393,6 +1405,11 @@ int32_t qpnp_adc_btm_scaler(struct qpnp_vadc_chip *chip,
	int64_t low_output = 0, high_output = 0;
	int rc = 0;

	if (param->adc_tm_hc) {
		pr_err("Update scaling for VADC_TM_HC\n");
		return -EINVAL;
	}

	qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_RATIOMETRIC);

	pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
@@ -1446,6 +1463,11 @@ int32_t qpnp_adc_qrd_skuh_btm_scaler(struct qpnp_vadc_chip *chip,
	int64_t low_output = 0, high_output = 0;
	int rc = 0;

	if (param->adc_tm_hc) {
		pr_err("Update scaling for VADC_TM_HC\n");
		return -EINVAL;
	}

	qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_RATIOMETRIC);

	pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
@@ -1499,6 +1521,11 @@ int32_t qpnp_adc_qrd_skut1_btm_scaler(struct qpnp_vadc_chip *chip,
	int64_t low_output = 0, high_output = 0;
	int rc = 0;

	if (param->adc_tm_hc) {
		pr_err("Update scaling for VADC_TM_HC\n");
		return -EINVAL;
	}

	qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_RATIOMETRIC);

	pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
@@ -1552,6 +1579,11 @@ int32_t qpnp_adc_smb_btm_rscaler(struct qpnp_vadc_chip *chip,
	int64_t low_output = 0, high_output = 0;
	int rc = 0;

	if (param->adc_tm_hc) {
		pr_err("Update scaling for VADC_TM_HC\n");
		return -EINVAL;
	}

	qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_RATIOMETRIC);

	pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
+5 −1
Original line number Diff line number Diff line
@@ -1642,8 +1642,12 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
	vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy =
				(calib_read_1 - calib_read_2);

	if (calib_type == CALIB_ABSOLUTE)
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx
						= QPNP_ADC_625_UV;
	else if (calib_type == ADC_HC_ABS_CAL)
		vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx
						= QPNP_ADC_1P25_UV;
	vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_vref =
					calib_read_1;
	vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd =
+245 −162
Original line number Diff line number Diff line
@@ -250,6 +250,8 @@ struct qpnp_adc_tm_sensor {
	bool				thermal_node;
	uint32_t			scale_type;
	struct list_head		thr_list;
	bool				high_thr_triggered;
	bool				low_thr_triggered;
};

struct qpnp_adc_tm_chip {
@@ -501,8 +503,8 @@ static int32_t qpnp_adc_tm_rc_check_channel_en(struct qpnp_adc_tm_chip *chip)
		}

		adc_tm_ctl &= QPNP_BTM_Mn_MEAS_EN;
		status_low &= QPNP_BTM_Mn_LOW_THR_INT_EN;
		status_high &= QPNP_BTM_Mn_HIGH_THR_INT_EN;
		status_low = adc_tm_ctl & QPNP_BTM_Mn_LOW_THR_INT_EN;
		status_high = adc_tm_ctl & QPNP_BTM_Mn_HIGH_THR_INT_EN;

		/* Enable only if there are pending measurement requests */
		if ((adc_tm_ctl && status_high) ||
@@ -1497,11 +1499,13 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
		return -EINVAL;

	mutex_lock(&chip->adc->adc_lock);

	btm_chan = adc_tm->btm_channel_num;
	rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
	if (rc < 0) {
		pr_err("Invalid btm channel idx\n");
		return rc;
		goto fail;
	}

	if (mode == THERMAL_DEVICE_ENABLED) {
@@ -1527,14 +1531,14 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
			rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
			if (rc) {
				pr_err("adc-tm configure failed with %d\n", rc);
				return -EINVAL;
				goto fail;
			}
		} else {
			rc = qpnp_adc_tm_hc_configure(chip,
							chip->adc->amux_prop);
			if (rc) {
				pr_err("hc configure failed with %d\n", rc);
				return -EINVAL;
				goto fail;
			}
		}
	} else if (mode == THERMAL_DEVICE_DISABLED) {
@@ -1545,7 +1549,7 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
			rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
			if (rc < 0) {
				pr_err("adc-tm single mode select failed\n");
				return rc;
				goto fail;
			}
		}

@@ -1553,7 +1557,7 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
		rc = qpnp_adc_tm_disable(chip);
		if (rc < 0) {
			pr_err("adc-tm disable failed\n");
			return rc;
			goto fail;
		}

		if (!chip->adc_tm_hc) {
@@ -1561,14 +1565,14 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
			rc = qpnp_adc_tm_req_sts_check(chip);
			if (rc < 0) {
				pr_err("adc-tm req_sts check failed\n");
				return rc;
				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 update failed\n");
				return rc;
				goto fail;
			}
		} else {
			rc = qpnp_adc_tm_reg_update(chip,
@@ -1576,19 +1580,22 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
				QPNP_BTM_Mn_MEAS_EN, false);
			if (rc < 0) {
				pr_err("multi measurement disable failed\n");
				return rc;
				goto fail;
			}
		}

		rc = qpnp_adc_tm_enable_if_channel_meas(chip);
		if (rc < 0) {
			pr_err("re-enabling measurement failed\n");
			return rc;
			goto fail;
		}
	}

	adc_tm->mode = mode;

fail:
	mutex_unlock(&chip->adc->adc_lock);

	return 0;
}

@@ -2096,35 +2103,15 @@ fail:
	return rc;
}

static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
static int qpnp_adc_tm_disable_rearm_high_thresholds(
			struct qpnp_adc_tm_chip *chip, int sensor_num)
{
	u8 sensor_mask = 0, notify_check = 0;
	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
	uint32_t btm_chan_num = 0;

	struct qpnp_adc_thr_client_info *client_info = NULL;
	struct list_head *thr_list;

	if (qpnp_adc_tm_is_valid(chip))
		return -ENODEV;

	mutex_lock(&chip->adc->adc_lock);

	if (!chip->adc_tm_hc) {
		rc = qpnp_adc_tm_req_sts_check(chip);
		if (rc) {
			pr_err("adc-tm-tm req sts check failed with %d\n", rc);
			goto fail;
		}
	}

	if (chip->th_info.adc_tm_high_enable) {
		sensor_notify_num = chip->th_info.adc_tm_high_enable;
		while (i < chip->max_channels_available) {
			if ((sensor_notify_num & 0x1) == 1)
				sensor_num = i;
			sensor_notify_num >>= 1;
			i++;
		}
	uint32_t btm_chan_num = 0;
	u8 sensor_mask = 0, notify_check = 0;
	int rc = 0;

	btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
	pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
@@ -2132,8 +2119,10 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
		chip->th_info.adc_tm_low_enable,
		chip->th_info.qpnp_adc_tm_meas_en);
	if (!chip->sensor[sensor_num].thermal_node) {
			/* For non thermal registered clients
				such as usb_id, vbatt, pmic_therm */
		/*
		 * For non thermal registered clients 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,
@@ -2141,13 +2130,24 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
		if (rc < 0 || !notify_check) {
			pr_debug("Calib recheck re-armed rc=%d\n", rc);
			chip->th_info.adc_tm_high_enable = 0;
				goto fail;
			return rc;
		}
	} else {
			/* Uses the thermal sysfs registered device to disable
				the corresponding high voltage threshold which
				 is triggered by low temp */
		/*
		 * Uses the thermal sysfs registered device to disable
		 * the corresponding high voltage threshold which
		 * is triggered by low temp
		 */
		sensor_mask = 1 << sensor_num;
		pr_debug("thermal node with mask:%x\n", sensor_mask);
		rc = qpnp_adc_tm_activate_trip_type(
			chip->sensor[sensor_num].tz_dev,
			ADC_TM_TRIP_LOW_COOL,
			THERMAL_TRIP_ACTIVATION_DISABLED);
		if (rc < 0) {
			pr_err("notify error:%d\n", sensor_num);
			return rc;
		}
	}
	list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
		client_info = list_entry(thr_list,
@@ -2164,33 +2164,64 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
						ADC_TM_HIGH_THR_DISABLE;
		}
	}
	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);

	if (!chip->adc_tm_hc) {
		rc = qpnp_adc_tm_reg_update(chip,
			QPNP_ADC_TM_MULTI_MEAS_EN,
			sensor_mask, false);
		if (rc < 0) {
			pr_err("multi meas disable failed\n");
			return rc;
		}
	} else {
		rc = qpnp_adc_tm_reg_update(chip,
			QPNP_BTM_Mn_EN(sensor_num),
			QPNP_BTM_Mn_MEAS_EN, false);
		if (rc < 0) {
			pr_err("multi meas disable failed\n");
			return rc;
		}
	}

	rc = qpnp_adc_tm_enable_if_channel_meas(chip);
	if (rc < 0) {
		pr_err("re-enabling measurement failed\n");
		return rc;
	}

	if (chip->th_info.adc_tm_low_enable) {
		sensor_notify_num = chip->th_info.adc_tm_low_enable;
		i = 0;
		while (i < chip->max_channels_available) {
			if ((sensor_notify_num & 0x1) == 1)
				sensor_num = i;
			sensor_notify_num >>= 1;
			i++;
	queue_work(chip->sensor[sensor_num].req_wq,
				&chip->sensor[sensor_num].work);

	return rc;
}

static int qpnp_adc_tm_disable_rearm_low_thresholds(
			struct qpnp_adc_tm_chip *chip, int sensor_num)
{
	struct qpnp_adc_thr_client_info *client_info = NULL;
	struct list_head *thr_list;
	uint32_t btm_chan_num = 0;
	u8 sensor_mask = 0, notify_check = 0;
	int rc = 0;

	btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
	pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
		sensor_num, chip->th_info.adc_tm_high_enable,
		chip->th_info.adc_tm_low_enable,
		chip->th_info.qpnp_adc_tm_meas_en);
	if (!chip->sensor[sensor_num].thermal_node) {
			/* For non thermal registered clients
				such as usb_id, vbatt, pmic_therm */
		/*
		 * 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);
			chip->th_info.adc_tm_low_enable = 0;
				goto fail;
			return rc;
		}
		sensor_mask = 1 << sensor_num;
		rc = qpnp_adc_tm_reg_update(chip,
@@ -2198,12 +2229,15 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
			sensor_mask, false);
		if (rc < 0) {
			pr_err("low threshold int read failed\n");
				goto fail;
			return rc;
		}
	} else {
			/* Uses the thermal sysfs registered device to disable
				the corresponding low voltage threshold which
				 is triggered by high temp */
		/*
		 * Uses the thermal sysfs registered device to disable
		 * the corresponding high voltage threshold which
		 * is triggered by low temp
		 */
		sensor_mask = 1 << sensor_num;
		pr_debug("thermal node with mask:%x\n", sensor_mask);
		rc = qpnp_adc_tm_activate_trip_type(
			chip->sensor[sensor_num].tz_dev,
@@ -2211,15 +2245,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
			THERMAL_TRIP_ACTIVATION_DISABLED);
		if (rc < 0) {
			pr_err("notify error:%d\n", sensor_num);
				goto fail;
			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);
		if (client_info->low_thr_set) {
				/* mark the corresponding clients threshold
					as not set */
			client_info->low_thr_set = false;
			client_info->notify_low_thr = true;
			if (client_info->state_req_copy ==
@@ -2231,27 +2263,23 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
						ADC_TM_LOW_THR_DISABLE;
		}
	}
	}

	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);

	if (chip->th_info.adc_tm_high_enable ||
				chip->th_info.adc_tm_low_enable) {
	if (!chip->adc_tm_hc) {
		rc = qpnp_adc_tm_reg_update(chip,
			QPNP_ADC_TM_MULTI_MEAS_EN,
			sensor_mask, false);
		if (rc < 0) {
			pr_err("multi meas disable failed\n");
				goto fail;
			return rc;
		}
	} else {
		rc = qpnp_adc_tm_reg_update(chip,
				QPNP_BTM_Mn_EN(sensor_mask),
			QPNP_BTM_Mn_EN(sensor_num),
			QPNP_BTM_Mn_MEAS_EN, false);
		if (rc < 0) {
			pr_err("multi meas disable failed\n");
				goto fail;
			return rc;
		}
	}

@@ -2260,16 +2288,62 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
		pr_err("re-enabling measurement failed\n");
		return rc;
	}
	} else
		pr_debug("No threshold status enable %d for high/low??\n",
								sensor_mask);

	queue_work(chip->sensor[sensor_num].req_wq,
				&chip->sensor[sensor_num].work);

	return rc;
}

static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
{
	int rc = 0, sensor_num = 0;

	if (qpnp_adc_tm_is_valid(chip))
		return -ENODEV;

	pr_debug("%s\n", __func__);

	mutex_lock(&chip->adc->adc_lock);

	if (!chip->adc_tm_hc) {
		rc = qpnp_adc_tm_req_sts_check(chip);
		if (rc) {
			pr_err("adc-tm-tm req sts check failed with %d\n", rc);
			goto fail;
		}
	}

	while (sensor_num < chip->max_channels_available) {
		if (chip->sensor[sensor_num].high_thr_triggered) {
			rc = qpnp_adc_tm_disable_rearm_high_thresholds(
					chip, sensor_num);
			if (rc) {
				pr_err("rearm threshold failed\n");
				goto fail;
			}
			chip->sensor[sensor_num].high_thr_triggered = false;
		}
		sensor_num++;
	}

	sensor_num = 0;
	while (sensor_num < chip->max_channels_available) {
		if (chip->sensor[sensor_num].low_thr_triggered) {
			rc = qpnp_adc_tm_disable_rearm_low_thresholds(
					chip, sensor_num);
			if (rc) {
				pr_err("rearm threshold failed\n");
				goto fail;
			}
			chip->sensor[sensor_num].low_thr_triggered = false;
		}
		sensor_num++;
	}

fail:
	mutex_unlock(&chip->adc->adc_lock);

	if (chip->th_info.adc_tm_high_enable || chip->th_info.adc_tm_low_enable)
		queue_work(chip->sensor[sensor_num].req_wq,
				&chip->sensor[sensor_num].work);
	if (rc < 0 || (!chip->th_info.adc_tm_high_enable &&
					!chip->th_info.adc_tm_low_enable))
		atomic_dec(&chip->wq_cnt);
@@ -2290,6 +2364,8 @@ static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
		chip->adc_vote_enable = false;
	}

	pr_debug("thr:0x%x\n", chip->th_info.adc_tm_high_enable);

	rc = qpnp_adc_tm_read_status(chip);
	if (rc < 0)
		pr_err("adc-tm high thr work failed\n");
@@ -2393,6 +2469,8 @@ static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
		chip->adc_vote_enable = false;
	}

	pr_debug("thr:0x%x\n", chip->th_info.adc_tm_low_enable);

	rc = qpnp_adc_tm_read_status(chip);
	if (rc < 0)
		pr_err("adc-tm low thr work failed\n");
@@ -2483,7 +2561,7 @@ static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)

static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
			u8 status_low, u8 status_high, int i,
			int sensor_low_notify_num, int sensor_high_notify_num)
			int *sensor_low_notify_num, int *sensor_high_notify_num)
{
	int rc = 0;
	u8 ctl = 0, sensor_mask = 0;
@@ -2523,7 +2601,8 @@ static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
					return IRQ_HANDLED;
				}
			}
			sensor_low_notify_num |= (status_low & 0x1);
			*sensor_low_notify_num |= (status_low & 0x1);
			chip->sensor[i].low_thr_triggered = true;
		}

		if ((status_high & 0x1) && (ctl & QPNP_BTM_Mn_MEAS_EN) &&
@@ -2553,7 +2632,8 @@ static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
					return IRQ_HANDLED;
				}
			}
			sensor_high_notify_num |= (status_high & 0x1);
			*sensor_high_notify_num |= (status_high & 0x1);
			chip->sensor[i].high_thr_triggered = true;
		}
	}

@@ -2590,7 +2670,8 @@ static irqreturn_t qpnp_adc_tm_rc_thr_isr(int irq, void *data)
	while (i < chip->max_channels_available) {
		rc = qpnp_adc_tm_rc_check_sensor_trip(chip,
				status_low, status_high, i,
				sensor_low_notify_num, sensor_high_notify_num);
				&sensor_low_notify_num,
				&sensor_high_notify_num);
		if (rc) {
			pr_err("Sensor trip read failed\n");
			return IRQ_HANDLED;
@@ -2600,14 +2681,15 @@ static irqreturn_t qpnp_adc_tm_rc_thr_isr(int irq, void *data)
		i++;
	}

	if (sensor_low_notify_num || sensor_high_notify_num)
	if (sensor_low_notify_num) {
		atomic_inc(&chip->wq_cnt);

	if (sensor_low_notify_num)
		queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work);
	}

	if (sensor_high_notify_num)
	if (sensor_high_notify_num) {
		atomic_inc(&chip->wq_cnt);
		queue_work(chip->high_thr_wq, &chip->trigger_high_thr_work);
	}

	return IRQ_HANDLED;
}
@@ -2710,6 +2792,7 @@ int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
					channel, scale_type, dt_index);
	param->gain_num = qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
	param->gain_den = qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
	param->adc_tm_hc = chip->adc_tm_hc;
	chip->adc->amux_prop->amux_channel = channel;
	chip->adc->amux_prop->decimation =
			chip->adc->adc_channels[dt_index].adc_decimation;
+3 −0
Original line number Diff line number Diff line
@@ -242,6 +242,7 @@ enum qpnp_iadc_channels {
#define QPNP_ADC_HWMON_NAME_LENGTH				64
#define QPNP_MAX_PROP_NAME_LEN					32
#define QPNP_THERMALNODE_NAME_LENGTH                            25
#define QPNP_ADC_1P25_UV					1250000

/* Structure device for qpnp vadc */
struct qpnp_vadc_chip;
@@ -950,6 +951,7 @@ enum qpnp_state_request {
 * @low_temp: Low temperature threshold for which notification is requested.
 * @high_thr_voltage: High voltage for which notification is requested.
 * @low_thr_voltage: Low voltage for which notification is requested.
 * @adc_tm_hc: Represents the refreshed BTM register design.
 * @state_request: Enable/disable the corresponding high and low temperature
 *		thresholds.
 * @timer_interval1: Select polling rate from qpnp_adc_meas_timer_1 type.
@@ -972,6 +974,7 @@ struct qpnp_adc_tm_btm_param {
	int32_t					low_thr;
	int32_t					gain_num;
	int32_t					gain_den;
	bool					adc_tm_hc;
	enum qpnp_vadc_channels			channel;
	enum qpnp_state_request			state_request;
	enum qpnp_adc_meas_timer_1		timer_interval;