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

Commit 9e8c8d31 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-voltage: Add measurement interval mode"

parents d9300d9a 31d7344d
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -13,7 +13,10 @@ Required properties:
- address-cells : Must be one.
- size-cells : Must be zero.
- interrupts : The USR bank peripheral VADC interrupt.
- interrupt-names : Should contain "eoc-int-en-set".
- interrupt-names : Should contain "eoc-int-en-set" for EOC,
		"high-thr-en-set" for high threshold interrupts and
		"low-thr-en-set" for low threshold interrupts. High and low threshold
		interrupts are to be enabled if VADC_USR needs to support recurring measurement.
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.

@@ -25,6 +28,9 @@ Optional properties:
- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
		    PMIC type and revision for applying the appropriate temperature
		    compensation parameters.
-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.

Client required property:
- qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
+467 −25
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@
#define QPNP_VADC_STATUS1_REQ_STS				BIT(1)
#define QPNP_VADC_STATUS1_EOC					BIT(0)
#define QPNP_VADC_STATUS1_REQ_STS_EOC_MASK			0x3
#define QPNP_VADC_STATUS1_OP_MODE_MASK				0x18
#define QPNP_VADC_MEAS_INT_MODE					0x2

#define QPNP_VADC_STATUS2					0x9
#define QPNP_VADC_STATUS2_CONV_SEQ_STATE				6
#define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG			BIT(1)
@@ -55,34 +58,31 @@
#define QPNP_VADC_CONV_TIMEOUT_ERR				2

#define QPNP_VADC_MODE_CTL					0x40
#define QPNP_VADC_OP_MODE_SHIFT					4
#define QPNP_VADC_OP_MODE_SHIFT					3
#define QPNP_VADC_VREF_XO_THM_FORCE				BIT(2)
#define QPNP_VADC_AMUX_TRIM_EN					BIT(1)
#define QPNP_VADC_ADC_TRIM_EN					BIT(0)
#define QPNP_VADC_TRIM_EN					BIT(0)
#define QPNP_VADC_EN_CTL1					0x46
#define QPNP_VADC_ADC_EN					BIT(7)
#define QPNP_VADC_ADC_CH_SEL_CTL					0x48
#define QPNP_VADC_ADC_DIG_PARAM					0x50
#define QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT			3
#define QPNP_VADC_EN						BIT(7)
#define QPNP_VADC_CH_SEL_CTL					0x48
#define QPNP_VADC_DIG_PARAM					0x50
#define QPNP_VADC_DIG_DEC_RATIO_SEL_SHIFT			3
#define QPNP_VADC_HW_SETTLE_DELAY				0x51
#define QPNP_VADC_CONV_REQ					0x52
#define QPNP_VADC_CONV_REQ_SET					BIT(7)
#define QPNP_VADC_CONV_SEQ_CTL					0x54
#define QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT				4
#define QPNP_VADC_CONV_SEQ_TRIG_CTL				0x55
#define QPNP_VADC_MEAS_INTERVAL_CTL				0x57
#define QPNP_VADC_CONV_SEQ_FALLING_EDGE				0x0
#define QPNP_VADC_CONV_SEQ_RISING_EDGE				0x1
#define QPNP_VADC_CONV_SEQ_EDGE_SHIFT				7
#define QPNP_VADC_FAST_AVG_CTL					0x5a

#define QPNP_VADC_M0_LOW_THR_LSB					0x5c
#define QPNP_VADC_M0_LOW_THR_MSB					0x5d
#define QPNP_VADC_M0_HIGH_THR_LSB				0x5e
#define QPNP_VADC_M0_HIGH_THR_MSB				0x5f
#define QPNP_VADC_M1_LOW_THR_LSB					0x69
#define QPNP_VADC_M1_LOW_THR_MSB					0x6a
#define QPNP_VADC_M1_HIGH_THR_LSB				0x6b
#define QPNP_VADC_M1_HIGH_THR_MSB				0x6c
#define QPNP_VADC_LOW_THR_LSB					0x5c
#define QPNP_VADC_LOW_THR_MSB					0x5d
#define QPNP_VADC_HIGH_THR_LSB					0x5e
#define QPNP_VADC_HIGH_THR_MSB					0x5f
#define QPNP_VADC_ACCESS					0xd0
#define QPNP_VADC_ACCESS_DATA					0xa5
#define QPNP_VADC_PERH_RESET_CTL3				0xda
@@ -100,6 +100,21 @@
#define QPNP_VADC_CONV_TIME_MAX					2100
#define QPNP_ADC_COMPLETION_TIMEOUT				HZ
#define QPNP_VADC_ERR_COUNT					20
#define QPNP_OP_MODE_SHIFT					3

#define QPNP_VADC_THR_LSB_MASK(val)				(val & 0xff)
#define QPNP_VADC_THR_MSB_MASK(val)			((val & 0xff00) >> 8)
#define QPNP_MIN_TIME						2000
#define QPNP_MAX_TIME						2000
#define QPNP_RETRY						100

struct qpnp_vadc_mode_state {
	bool				meas_int_mode;
	bool				meas_int_request_in_queue;
	bool				vadc_meas_int_enable;
	struct qpnp_adc_tm_btm_param	*param;
	struct qpnp_adc_amux		vadc_meas_amux;
};

struct qpnp_vadc_chip {
	struct device			*dev;
@@ -115,6 +130,11 @@ struct qpnp_vadc_chip {
	bool				vadc_poll_eoc;
	u8				revision_ana_minor;
	u8				revision_dig_major;
	struct workqueue_struct		*high_thr_wq;
	struct workqueue_struct		*low_thr_wq;
	struct work_struct		trigger_high_thr_work;
	struct work_struct		trigger_low_thr_work;
	struct qpnp_vadc_mode_state	*state_copy;
	struct sensor_device_attribute	sens_attr[0];
};

@@ -135,6 +155,11 @@ static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
	[SCALE_NCP_03WF683_THERM] = {qpnp_adc_scale_therm_ncp03},
};

static struct qpnp_adc_tm_reverse_scale_fn adc_vadc_rscale_fn[] = {
	[SCALE_RVADC_ABSOLUTE] = {qpnp_adc_absolute_rthr},
	[SCALE_RVADC_PMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
};

static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
								u8 *data)
{
@@ -202,12 +227,25 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
	return 0;
}

static int32_t qpnp_vadc_mode_select(struct qpnp_vadc_chip *vadc, u8 mode_ctl)
{
	int rc;

	mode_ctl |= (QPNP_VADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN);

	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_MODE_CTL, mode_ctl);
	if (rc < 0)
		pr_err("vadc write mode selection err:%d\n", rc);

	return rc;
}

static int32_t qpnp_vadc_enable(struct qpnp_vadc_chip *vadc, bool state)
{
	int rc = 0;
	u8 data = 0;

	data = QPNP_VADC_ADC_EN;
	data = QPNP_VADC_EN;
	if (state) {
		rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
					data);
@@ -217,7 +255,7 @@ static int32_t qpnp_vadc_enable(struct qpnp_vadc_chip *vadc, bool state)
		}
	} else {
		rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
					(~data & QPNP_VADC_ADC_EN));
					(~data & QPNP_VADC_EN));
		if (rc < 0) {
			pr_err("VADC disable failed\n");
			return rc;
@@ -238,13 +276,13 @@ static int32_t qpnp_vadc_status_debug(struct qpnp_vadc_chip *vadc)
		return rc;
	}

	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, &dig);
	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_DIG_PARAM, &dig);
	if (rc < 0) {
		pr_err("digital param read failed with %d\n", rc);
		return rc;
	}

	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL, &chan);
	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_CH_SEL_CTL, &chan);
	if (rc < 0) {
		pr_err("channel read failed with %d\n", rc);
		return rc;
@@ -288,16 +326,15 @@ static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,

	/* Mode selection */
	mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
			(QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
			(QPNP_VADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_MODE_CTL, mode_ctrl);
	if (rc < 0) {
		pr_err("Mode configure write error\n");
		return rc;
	}


	/* Channel selection */
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL,
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CH_SEL_CTL,
						chan_prop->amux_channel);
	if (rc < 0) {
		pr_err("Channel configure error\n");
@@ -306,8 +343,8 @@ static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,

	/* Digital parameter setup */
	decimation = chan_prop->decimation <<
				QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, decimation);
				QPNP_VADC_DIG_DEC_RATIO_SEL_SHIFT;
	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_DIG_PARAM, decimation);
	if (rc < 0) {
		pr_err("Digital parameter configure write error\n");
		return rc;
@@ -321,6 +358,10 @@ static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,
		return rc;
	}

	pr_debug("mode:%d, channel:%d, decimation:%d, hw_settle:%d\n",
		mode_ctrl, chan_prop->amux_channel, decimation,
					chan_prop->hw_settle_time);

	if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
					QPNP_VADC_OP_MODE_SHIFT)) {
		/* Normal measurement mode */
@@ -472,6 +513,33 @@ static void qpnp_vadc_work(struct work_struct *work)
	return;
}

static void qpnp_vadc_low_thr_fn(struct work_struct *work)
{
	struct qpnp_vadc_chip *vadc = container_of(work,
			struct qpnp_vadc_chip, trigger_low_thr_work);

	vadc->state_copy->meas_int_mode = false;
	vadc->state_copy->meas_int_request_in_queue = false;
	vadc->state_copy->param->threshold_notification(
			ADC_TM_LOW_STATE,
			vadc->state_copy->param->btm_ctx);

	return;
}

static void qpnp_vadc_high_thr_fn(struct work_struct *work)
{
	struct qpnp_vadc_chip *vadc = container_of(work,
			struct qpnp_vadc_chip, trigger_high_thr_work);

	vadc->state_copy->meas_int_mode = false;
	vadc->state_copy->meas_int_request_in_queue = false;
	vadc->state_copy->param->threshold_notification(
			ADC_TM_HIGH_STATE,
			vadc->state_copy->param->btm_ctx);

	return;
}
static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
{
	struct qpnp_vadc_chip *vadc = dev_id;
@@ -481,6 +549,34 @@ static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
	return IRQ_HANDLED;
}

static irqreturn_t qpnp_vadc_low_thr_isr(int irq, void *data)
{
	struct qpnp_vadc_chip *vadc = data;
	u8 mode_ctl = 0;

	mode_ctl = ADC_OP_NORMAL_MODE;
	/* Set measurement in single measurement mode */
	qpnp_vadc_mode_select(vadc, mode_ctl);
	qpnp_vadc_enable(vadc, false);
	schedule_work(&vadc->trigger_low_thr_work);

	return IRQ_HANDLED;
}

static irqreturn_t qpnp_vadc_high_thr_isr(int irq, void *data)
{
	struct qpnp_vadc_chip *vadc = data;
	u8 mode_ctl = 0;

	mode_ctl = ADC_OP_NORMAL_MODE;
	/* Set measurement in single measurement mode */
	qpnp_vadc_mode_select(vadc, mode_ctl);
	qpnp_vadc_enable(vadc, false);
	schedule_work(&vadc->trigger_high_thr_work);

	return IRQ_HANDLED;
}

static int32_t qpnp_vadc_version_check(struct qpnp_vadc_chip *dev)
{
	uint8_t revision;
@@ -1178,6 +1274,123 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
}
EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);

static int32_t qpnp_vadc_wait_for_req_sts_check(struct qpnp_vadc_chip *vadc)
{
	u8 status1 = 0;
	int rc, count = 0;

	/* Re-enable the peripheral */
	rc = qpnp_vadc_enable(vadc, true);
	if (rc) {
		pr_err("vadc re-enable peripheral failed with %d\n", rc);
		return rc;
	}

	/* The VADC_TM bank needs to be disabled for new conversion request */
	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
	if (rc) {
		pr_err("vadc read status1 failed with %d\n", rc);
		return rc;
	}

	/* Disable the bank if a conversion is occuring */
	while ((status1 & QPNP_VADC_STATUS1_REQ_STS) && (count < QPNP_RETRY)) {
		/* Wait time is based on the optimum sampling rate
		 * and adding enough time buffer to account for ADC conversions
		 * occuring on different peripheral banks */
		usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
		rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
		if (rc < 0) {
			pr_err("vadc disable failed with %d\n", rc);
			return rc;
		}
		count++;
	}

	if (count >= QPNP_RETRY)
		pr_err("QPNP vadc status req bit did not fall low!!\n");

	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);

	/* Disable the peripheral */
	rc = qpnp_vadc_enable(vadc, false);
	if (rc < 0)
		pr_err("vadc peripheral disable failed with %d\n", rc);

	return rc;
}

static int32_t qpnp_vadc_manage_meas_int_requests(struct qpnp_vadc_chip *chip)
{
	struct qpnp_vadc_chip *vadc = dev_get_drvdata(chip->dev);
	int rc = 0, dt_index = 0;
	u8 mode_ctl = 0;

	pr_debug("meas_int_mode:0x%x, mode_ctl:%0x\n",
		vadc->state_copy->meas_int_mode, mode_ctl);

	if (vadc->state_copy->meas_int_mode) {
		pr_debug("meas interval in progress. Procced to disable it\n");
		/* measurement interval in progress. Proceed to disable it */
		mode_ctl = ADC_OP_NORMAL_MODE;
		rc = qpnp_vadc_mode_select(vadc, mode_ctl);
		if (rc < 0) {
			pr_err("NORM mode select failed with %d\n", rc);
			return rc;
		}

		/* Disable bank */
		rc = qpnp_vadc_enable(vadc, false);
		if (rc) {
			pr_err("Disable bank failed with %d\n", rc);
			return rc;
		}

		/* Check if a conversion is in progress */
		rc = qpnp_vadc_wait_for_req_sts_check(vadc);
		if (rc < 0) {
			pr_err("req_sts check failed with %d\n", rc);
			return rc;
		}

		vadc->state_copy->meas_int_mode = false;
		vadc->state_copy->meas_int_request_in_queue = true;
	} else if (vadc->state_copy->meas_int_request_in_queue) {
		/* put the meas interval back in queue */
		pr_debug("put meas interval back in queue\n");
		vadc->adc->amux_prop->amux_channel =
				vadc->state_copy->vadc_meas_amux.channel_num;
		while ((vadc->adc->adc_channels[dt_index].channel_num
			!= vadc->adc->amux_prop->amux_channel) &&
			(dt_index < vadc->max_channels_available))
			dt_index++;
		if (dt_index >= vadc->max_channels_available) {
			pr_err("not a valid VADC channel\n");
			rc = -EINVAL;
			return rc;
		}

		vadc->adc->amux_prop->decimation =
			vadc->adc->amux_prop->decimation;
		vadc->adc->amux_prop->hw_settle_time =
			vadc->adc->amux_prop->hw_settle_time;
		vadc->adc->amux_prop->fast_avg_setup =
			vadc->adc->amux_prop->fast_avg_setup;
		vadc->adc->amux_prop->mode_sel = ADC_OP_MEASUREMENT_INTERVAL;
		rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
		if (rc) {
			pr_err("vadc configure failed with %d\n", rc);
			return rc;
		}

		vadc->state_copy->meas_int_mode = true;
		vadc->state_copy->meas_int_request_in_queue = false;
	}
	dev_set_drvdata(vadc->dev, vadc);

	return 0;
}

struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev, const char *name)
{
	struct qpnp_vadc_chip *vadc;
@@ -1211,6 +1424,9 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,

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

	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)
@@ -1346,6 +1562,9 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);

fail_unlock:
	if (vadc->state_copy->vadc_meas_int_enable)
		qpnp_vadc_manage_meas_int_requests(vadc);

	mutex_unlock(&vadc->adc->adc_lock);

	return rc;
@@ -1502,6 +1721,175 @@ fail:
}
EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);

static int32_t qpnp_vadc_thr_update(struct qpnp_vadc_chip *vadc,
					int32_t high_thr, int32_t low_thr)
{
	int rc = 0;

	pr_debug("client requested high:%d and low:%d\n",
		high_thr, low_thr);

	rc = qpnp_vadc_write_reg(vadc,
			QPNP_VADC_LOW_THR_LSB,
			QPNP_VADC_THR_LSB_MASK(low_thr));
	if (rc < 0) {
		pr_err("low threshold lsb setting failed, err:%d\n", rc);
		return rc;
	}

	rc = qpnp_vadc_write_reg(vadc,
			QPNP_VADC_LOW_THR_MSB,
			QPNP_VADC_THR_MSB_MASK(low_thr));
	if (rc < 0) {
		pr_err("low threshold msb setting failed, err:%d\n", rc);
		return rc;
	}

	rc = qpnp_vadc_write_reg(vadc,
			QPNP_VADC_HIGH_THR_LSB,
			QPNP_VADC_THR_LSB_MASK(high_thr));
	if (rc < 0) {
		pr_err("high threshold lsb setting failed, err:%d\n", rc);
		return rc;
	}

	rc = qpnp_vadc_write_reg(vadc,
			QPNP_VADC_HIGH_THR_MSB,
			QPNP_VADC_THR_MSB_MASK(high_thr));
	if (rc < 0) {
		pr_err("high threshold msb setting failed, err:%d\n", rc);
		return rc;
	}

	pr_debug("client requested high:%d and low:%d\n", high_thr, low_thr);

	return rc;
}

int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip,
					struct qpnp_adc_tm_btm_param *param)
{
	uint32_t channel, scale_type = 0;
	uint32_t low_thr = 0, high_thr = 0;
	int rc = 0, idx = 0;
	struct qpnp_vadc_chip *vadc = dev_get_drvdata(chip->dev);

	if (qpnp_vadc_is_valid(vadc))
		return -EPROBE_DEFER;

	if (!vadc->state_copy->vadc_meas_int_enable) {
		pr_err("Recurring measurement interval not available\n");
		return -EINVAL;
	}

	if (param->threshold_notification == NULL) {
		pr_debug("No notification for high/low temp??\n");
		return -EINVAL;
	}

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

	channel = param->channel;
	while (idx < vadc->max_channels_available) {
		if (vadc->adc->adc_channels[idx].channel_num == channel)
			break;
		 else
			idx++;
	}

	if (idx >= vadc->max_channels_available)  {
		pr_err("not a valid VADC channel\n");
		rc = -EINVAL;
		goto fail_unlock;
	}

	scale_type = vadc->adc->adc_channels[idx].adc_scale_fn;
	if (scale_type >= SCALE_RSCALE_NONE) {
		rc = -EBADF;
		goto fail_unlock;
	}

	pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
					channel, scale_type, idx);
	vadc->adc->amux_prop->amux_channel = channel;
	vadc->adc->amux_prop->decimation =
			vadc->adc->adc_channels[idx].adc_decimation;
	vadc->adc->amux_prop->hw_settle_time =
			vadc->adc->adc_channels[idx].hw_settle_time;
	vadc->adc->amux_prop->fast_avg_setup =
			vadc->adc->adc_channels[idx].fast_avg_setup;
	vadc->adc->amux_prop->mode_sel = ADC_OP_MEASUREMENT_INTERVAL;
	adc_vadc_rscale_fn[scale_type].chan(vadc, param,
			&low_thr, &high_thr);

	if (param->timer_interval >= ADC_MEAS1_INTERVAL_NONE) {
		pr_err("Invalid timer interval :%d\n", param->timer_interval);
		goto fail_unlock;
	}

	rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_MEAS_INTERVAL_CTL,
				param->timer_interval);
	if (rc) {
		pr_err("vadc meas timer failed with %d\n", rc);
		goto fail_unlock;
	}

	rc = qpnp_vadc_thr_update(vadc, high_thr, low_thr);
	if (rc) {
		pr_err("vadc thr update failed with %d\n", rc);
		goto fail_unlock;
	}

	rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
	if (rc) {
		pr_err("vadc configure failed with %d\n", rc);
		goto fail_unlock;
	}

	vadc->state_copy->meas_int_mode = true;
	vadc->state_copy->param = param;
	vadc->state_copy->vadc_meas_amux.channel_num = channel;
	vadc->state_copy->vadc_meas_amux.adc_decimation =
				vadc->adc->amux_prop->decimation;
	vadc->state_copy->vadc_meas_amux.hw_settle_time =
				vadc->adc->amux_prop->hw_settle_time;
	vadc->state_copy->vadc_meas_amux.fast_avg_setup =
				vadc->adc->amux_prop->fast_avg_setup;
	vadc->state_copy->meas_int_request_in_queue = false;
	dev_set_drvdata(vadc->dev, vadc);

fail_unlock:
	mutex_unlock(&vadc->adc->adc_lock);

	return rc;
}
EXPORT_SYMBOL(qpnp_vadc_channel_monitor);

int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip)
{
	struct qpnp_vadc_chip *vadc = dev_get_drvdata(chip->dev);
	u8 mode_ctl = 0;

	if (qpnp_vadc_is_valid(vadc))
		return -EPROBE_DEFER;

	if (!vadc->state_copy->vadc_meas_int_enable) {
		pr_err("Recurring measurement interval not available\n");
		return -EINVAL;
	}

	vadc->state_copy->meas_int_mode = false;
	vadc->state_copy->meas_int_request_in_queue = false;
	dev_set_drvdata(vadc->dev, vadc);
	mode_ctl = ADC_OP_NORMAL_MODE;
	/* Set measurement in single measurement mode */
	qpnp_vadc_mode_select(vadc, mode_ctl);
	qpnp_vadc_enable(vadc, false);

	return 0;
}
EXPORT_SYMBOL(qpnp_vadc_end_channel_monitor);

static ssize_t qpnp_adc_show(struct device *dev,
			struct device_attribute *devattr, char *buf)
{
@@ -1589,6 +1977,13 @@ static int qpnp_vadc_probe(struct spmi_device *spmi)
		return -ENOMEM;
	}

	vadc->state_copy = devm_kzalloc(&spmi->dev,
			sizeof(struct qpnp_vadc_mode_state), GFP_KERNEL);
	if (!vadc->state_copy) {
		dev_err(&spmi->dev, "Unable to allocate memory\n");
		return -ENOMEM;
	}

	vadc->adc = adc_qpnp;
	rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
	if (rc) {
@@ -1651,6 +2046,49 @@ static int qpnp_vadc_probe(struct spmi_device *spmi)
	} else
		device_init_wakeup(vadc->dev, 1);

	vadc->state_copy->vadc_meas_int_enable = of_property_read_bool(node,
						"qcom,vadc-meas-int-mode");
	if (vadc->state_copy->vadc_meas_int_enable) {
		vadc->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
						NULL, "high-thr-en-set");
		if (vadc->adc->adc_high_thr_irq < 0) {
			pr_err("Invalid irq\n");
			rc = -ENXIO;
			goto err_setup;
		}

		vadc->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
						NULL, "low-thr-en-set");
		if (vadc->adc->adc_low_thr_irq < 0) {
			pr_err("Invalid irq\n");
			rc = -ENXIO;
			goto err_setup;
		}

		rc = devm_request_irq(&spmi->dev, vadc->adc->adc_high_thr_irq,
					qpnp_vadc_high_thr_isr,
			IRQF_TRIGGER_RISING, "qpnp_vadc_high_interrupt", vadc);
		if (rc) {
			dev_err(&spmi->dev, "failed to request adc irq\n");
			goto err_setup;
		} else {
			enable_irq_wake(vadc->adc->adc_high_thr_irq);
		}

		rc = devm_request_irq(&spmi->dev, vadc->adc->adc_low_thr_irq,
					qpnp_vadc_low_thr_isr,
			IRQF_TRIGGER_RISING, "qpnp_vadc_low_interrupt", vadc);
		if (rc) {
			dev_err(&spmi->dev, "failed to request adc irq\n");
			goto err_setup;
		} else {
			enable_irq_wake(vadc->adc->adc_low_thr_irq);
		}
		INIT_WORK(&vadc->trigger_high_thr_work,
						qpnp_vadc_high_thr_fn);
		INIT_WORK(&vadc->trigger_low_thr_work, qpnp_vadc_low_thr_fn);
	}

	vadc->vadc_iadc_sync_lock = false;
	dev_set_drvdata(&spmi->dev, vadc);
	list_add(&vadc->list, &qpnp_vadc_device_list);
@@ -1698,8 +2136,11 @@ static int qpnp_vadc_suspend_noirq(struct device *dev)
	struct qpnp_vadc_chip *vadc = dev_get_drvdata(dev);
	u8 status = 0;

	if (vadc->vadc_poll_eoc) {
	qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status);
	if (((status & QPNP_VADC_STATUS1_OP_MODE_MASK) >>
		QPNP_VADC_OP_MODE_SHIFT) == QPNP_VADC_MEAS_INT_MODE) {
		pr_debug("Meas interval in progress\n");
	} else if (vadc->vadc_poll_eoc) {
		status &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
		pr_debug("vadc conversion status=%d\n", status);
		if (status != QPNP_VADC_STATUS1_EOC) {
@@ -1708,6 +2149,7 @@ static int qpnp_vadc_suspend_noirq(struct device *dev)
			return -EBUSY;
		}
	}

	return 0;
}

+37 −1
Original line number Diff line number Diff line
@@ -251,7 +251,6 @@ enum qpnp_adc_scale_fn_type {
	SCALE_NONE,
};


/**
 * enum qpnp_adc_tm_rscale_fn_type - Scaling function used to convert the
 *	channels input voltage/temperature to corresponding ADC code that is
@@ -274,6 +273,20 @@ enum qpnp_adc_tm_rscale_fn_type {
	SCALE_RSCALE_NONE,
};

/**
 * enum qpnp_vadc_rscale_fn_type - Scaling function used to convert the
 *	channels input voltage/temperature to corresponding ADC code that is
 *	applied for thresholds. Check the corresponding channels scaling to
 *	determine the appropriate temperature/voltage units that are passed
 *	to the scaling function. The order below should match the one in the
 *	driver for qpnp_adc_scale_fn[].
 */
enum qpnp_vadc_rscale_fn_type {
	SCALE_RVADC_ABSOLUTE = 0,
	SCALE_RVADC_PMIC_THERM = 3,
	SCALE_RVADC_SCALE_NONE,
};

/**
 * enum qpnp_adc_fast_avg_ctl - Provides ability to obtain single result
 *		from the ADC that is an average of multiple measurement
@@ -1511,6 +1524,24 @@ int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
 * returns internal mapped PMIC number and revision id.
 */
int qpnp_adc_get_revid_version(struct device *dev);
/**
 * qpnp_vadc_channel_monitor() - Configures kernel clients a channel to
 *		monitor the corresponding ADC channel for threshold detection.
 *		Driver passes the high/low voltage threshold along
 *		with the notification callback once the set thresholds
 *		are crossed.
 * @param:	Structure pointer of qpnp_adc_tm_btm_param type.
 *		Clients pass the low/high temperature along with the threshold
 *		notification callback.
 */
int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip,
					struct qpnp_adc_tm_btm_param *param);
/**
 * qpnp_vadc_end_channel_monitor() - Disables recurring measurement mode for
 *		VADC_USR and disables the bank.
 * @param:	device instance for the VADC
 */
int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip);
#else
static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
				uint32_t channel,
@@ -1656,6 +1687,11 @@ static inline int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
{ return -ENXIO; }
static inline int qpnp_adc_get_revid_version(struct device *dev)
{ return -ENXIO; }
static inline int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip,
					struct qpnp_adc_tm_btm_param *param)
{ return -ENXIO; }
static inline int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip)
{ return -ENXIO; }
#endif

/* Public API */