iio: pressure: dps310: Reset chip after timeout
authorEddie James <eajames@linux.ibm.com>
Thu, 15 Sep 2022 19:57:19 +0000 (14:57 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Oct 2022 10:34:19 +0000 (12:34 +0200)
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: ba6ec48e76bc ("iio: Add driver for Infineon DPS310")
Cc: <stable@vger.kernel.org>
Signed-off-by: Eddie James <eajames@linux.ibm.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220915195719.136812-3-eajames@linux.ibm.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iio/pressure/dps310.c

index 9b787ca..cf8b92f 100644 (file)
@@ -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 = {