Skip to content

Commit c92c1bc

Browse files
andy9a9jic23
authored andcommitted
iio: accel: fix ADXL355 startup race condition
There is an race-condition where device is not full working after SW reset. Therefore it's necessary to wait some time after reset and verify shadow registers values by reading and comparing the values before/after reset. This mechanism is described in datasheet at least from revision D. Fixes: 12ed278 ("iio: accel: Add driver support for ADXL355") Signed-off-by: Valek Andrej <andrej.v@skyrain.eu> Signed-off-by: Kessler Markus <markus.kessler@hilti.com> Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
1 parent e2cc390 commit c92c1bc

1 file changed

Lines changed: 39 additions & 5 deletions

File tree

drivers/iio/accel/adxl355_core.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
#define ADXL355_POWER_CTL_DRDY_MSK BIT(2)
5757
#define ADXL355_SELF_TEST_REG 0x2E
5858
#define ADXL355_RESET_REG 0x2F
59+
#define ADXL355_BASE_ADDR_SHADOW_REG 0x50
60+
#define ADXL355_SHADOW_REG_COUNT 5
5961

6062
#define ADXL355_DEVID_AD_VAL 0xAD
6163
#define ADXL355_DEVID_MST_VAL 0x1D
@@ -294,7 +296,12 @@ static void adxl355_fill_3db_frequency_table(struct adxl355_data *data)
294296
static int adxl355_setup(struct adxl355_data *data)
295297
{
296298
unsigned int regval;
299+
int retries = 5; /* the number is chosen based on empirical reasons */
297300
int ret;
301+
u8 *shadow_regs __free(kfree) = kzalloc(ADXL355_SHADOW_REG_COUNT, GFP_KERNEL);
302+
303+
if (!shadow_regs)
304+
return -ENOMEM;
298305

299306
ret = regmap_read(data->regmap, ADXL355_DEVID_AD_REG, &regval);
300307
if (ret)
@@ -321,14 +328,41 @@ static int adxl355_setup(struct adxl355_data *data)
321328
if (regval != ADXL355_PARTID_VAL)
322329
dev_warn(data->dev, "Invalid DEV ID 0x%02x\n", regval);
323330

324-
/*
325-
* Perform a software reset to make sure the device is in a consistent
326-
* state after start-up.
327-
*/
328-
ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
331+
/* Read shadow registers to be compared after reset */
332+
ret = regmap_bulk_read(data->regmap,
333+
ADXL355_BASE_ADDR_SHADOW_REG,
334+
shadow_regs, ADXL355_SHADOW_REG_COUNT);
329335
if (ret)
330336
return ret;
331337

338+
do {
339+
if (--retries == 0) {
340+
dev_err(data->dev, "Shadow registers mismatch\n");
341+
return -EIO;
342+
}
343+
344+
/*
345+
* Perform a software reset to make sure the device is in a consistent
346+
* state after start-up.
347+
*/
348+
ret = regmap_write(data->regmap, ADXL355_RESET_REG,
349+
ADXL355_RESET_CODE);
350+
if (ret)
351+
return ret;
352+
353+
/* Wait at least 5ms after software reset */
354+
usleep_range(5000, 10000);
355+
356+
/* Read shadow registers for comparison */
357+
ret = regmap_bulk_read(data->regmap,
358+
ADXL355_BASE_ADDR_SHADOW_REG,
359+
data->buffer.buf,
360+
ADXL355_SHADOW_REG_COUNT);
361+
if (ret)
362+
return ret;
363+
} while (memcmp(shadow_regs, data->buffer.buf,
364+
ADXL355_SHADOW_REG_COUNT));
365+
332366
ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
333367
ADXL355_POWER_CTL_DRDY_MSK,
334368
FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1));

0 commit comments

Comments
 (0)