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

Commit 37daa23f authored by Eddie James's avatar Eddie James Committed by Greg Kroah-Hartman
Browse files

iio: pressure: dps310: Reset chip after timeout



commit 7b4ab4abcea4c0c10b25187bf2569e5a07e9a20c upstream.

The DPS310 chip has been observed to get "stuck" such that pressure
and temperature measurements are never indicated as "ready" in the
MEAS_CFG register. The only solution is to reset the device and try
again. In order to avoid continual failures, use a boolean flag to
only try the reset after timeout once if errors persist.

Fixes: ba6ec48e ("iio: Add driver for Infineon DPS310")
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarEddie James <eajames@linux.ibm.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220915195719.136812-3-eajames@linux.ibm.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 228348a9
Loading
Loading
Loading
Loading
+64 −10
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ struct dps310_data {
	s32 c00, c10, c20, c30, c01, c11, c21;
	s32 pressure_raw;
	s32 temp_raw;
	bool timeout_recovery_failed;
};

static const struct iio_chan_spec dps310_channels[] = {
@@ -393,11 +394,69 @@ static int dps310_get_temp_k(struct dps310_data *data)
	return scale_factors[ilog2(rc)];
}

static int dps310_reset_wait(struct dps310_data *data)
{
	int rc;

	rc = regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
	if (rc)
		return rc;

	/* Wait for device chip access: 2.5ms in specification */
	usleep_range(2500, 12000);
	return 0;
}

static int dps310_reset_reinit(struct dps310_data *data)
{
	int rc;

	rc = dps310_reset_wait(data);
	if (rc)
		return rc;

	return dps310_startup(data);
}

static int dps310_ready_status(struct dps310_data *data, int ready_bit, int timeout)
{
	int sleep = DPS310_POLL_SLEEP_US(timeout);
	int ready;

	return regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, ready & ready_bit,
					sleep, timeout);
}

static int dps310_ready(struct dps310_data *data, int ready_bit, int timeout)
{
	int rc;

	rc = dps310_ready_status(data, ready_bit, timeout);
	if (rc) {
		if (rc == -ETIMEDOUT && !data->timeout_recovery_failed) {
			/* Reset and reinitialize the chip. */
			if (dps310_reset_reinit(data)) {
				data->timeout_recovery_failed = true;
			} else {
				/* Try again to get sensor ready status. */
				if (dps310_ready_status(data, ready_bit, timeout))
					data->timeout_recovery_failed = true;
				else
					return 0;
			}
		}

		return rc;
	}

	data->timeout_recovery_failed = false;
	return 0;
}

static int dps310_read_pres_raw(struct dps310_data *data)
{
	int rc;
	int rate;
	int ready;
	int timeout;
	s32 raw;
	u8 val[3];
@@ -409,9 +468,7 @@ static int dps310_read_pres_raw(struct dps310_data *data)
	timeout = DPS310_POLL_TIMEOUT_US(rate);

	/* Poll for sensor readiness; base the timeout upon the sample rate. */
	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
				      ready & DPS310_PRS_RDY,
				      DPS310_POLL_SLEEP_US(timeout), timeout);
	rc = dps310_ready(data, DPS310_PRS_RDY, timeout);
	if (rc)
		goto done;

@@ -448,7 +505,6 @@ static int dps310_read_temp_raw(struct dps310_data *data)
{
	int rc;
	int rate;
	int ready;
	int timeout;

	if (mutex_lock_interruptible(&data->lock))
@@ -458,10 +514,8 @@ static int dps310_read_temp_raw(struct dps310_data *data)
	timeout = DPS310_POLL_TIMEOUT_US(rate);

	/* Poll for sensor readiness; base the timeout upon the sample rate. */
	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
				      ready & DPS310_TMP_RDY,
				      DPS310_POLL_SLEEP_US(timeout), timeout);
	if (rc < 0)
	rc = dps310_ready(data, DPS310_TMP_RDY, timeout);
	if (rc)
		goto done;

	rc = dps310_read_temp_ready(data);
@@ -756,7 +810,7 @@ static void dps310_reset(void *action_data)
{
	struct dps310_data *data = action_data;

	regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
	dps310_reset_wait(data);
}

static const struct regmap_config dps310_regmap_config = {