Linux IIO development
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Andrej Valek <andrej.v@skyrain.eu>
Cc: linux-iio@vger.kernel.org, Lars-Peter Clausen <lars@metafoo.de>,
	Michael Hennerich <Michael.Hennerich@analog.com>,
	Puranjay Mohan <puranjay@kernel.org>,
	Kessler Markus <markus.kessler@hilti.com>
Subject: Re: [PATCH] drivers: iio: accel: fix ADX355 startup race condition
Date: Wed, 10 Sep 2025 19:30:49 +0100	[thread overview]
Message-ID: <20250910193049.145aa79e@jic23-huawei> (raw)
In-Reply-To: <20250909085528.68966-1-andrej.v@skyrain.eu>

On Tue,  9 Sep 2025 10:55:28 +0200
Andrej Valek <andrej.v@skyrain.eu> wrote:

> From: Valek Andrej <andrej.v@skyrain.eu>
Hi Valek,

Thanks for the patch. Small thing on patch title, don't include drivers.
It's a pain but you need to look at other patches to a given subsystem
to find out the preferred style.

> 
> 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.

I'm curious about the retries. Does the datasheet given any explanation for
why a reset might fail a few times before succeeding? 

> 
> Signed-off-by: Valek Andrej <andrej.v@skyrain.eu>
> Signed-off-by: Kessler Markus <markus.kessler@hilti.com>
> ---
>  drivers/iio/accel/adxl355_core.c | 48 ++++++++++++++++++++++++++++----
>  1 file changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
> index 2e00fd51b4d51..5386cd4766def 100644
> --- a/drivers/iio/accel/adxl355_core.c
> +++ b/drivers/iio/accel/adxl355_core.c
> @@ -56,6 +56,8 @@
>  #define  ADXL355_POWER_CTL_DRDY_MSK	BIT(2)
>  #define ADXL355_SELF_TEST_REG		0x2E
>  #define ADXL355_RESET_REG		0x2F
> +#define ADXL355_BASE_ADDR_SHADOW_REG	0x50
> +#define ADXL355_SHADOW_REG_COUNT	5
>  
>  #define ADXL355_DEVID_AD_VAL		0xAD
>  #define ADXL355_DEVID_MST_VAL		0x1D
> @@ -294,6 +296,9 @@ static void adxl355_fill_3db_frequency_table(struct adxl355_data *data)
>  static int adxl355_setup(struct adxl355_data *data)
>  {
>  	unsigned int regval;
> +	u8 shadow_regs[ADXL355_SHADOW_REG_COUNT];

Needs to be a DMA safe buffer.  We can't assume that regmap will always
bounce the data through one before passing it to the SPI controllers
that do sometimes require DMA safe buffers.    Add a buffer to end of
struct adxl355_data where you can take advantage of the forcing of appropriate
padding that is already going on there.

> +	bool shadow_regs_valid = false;
> +	int retries = 5; /* retries for reading shadow registers */

If this is an empirical number of retries say so. If it's on the datasheet
then mention that in the comment instead.

>  	int ret;
>  
>  	ret = regmap_read(data->regmap, ADXL355_DEVID_AD_REG, &regval);
> @@ -321,14 +326,47 @@ static int adxl355_setup(struct adxl355_data *data)
>  	if (regval != ADXL355_PARTID_VAL)
>  		dev_warn(data->dev, "Invalid DEV ID 0x%02x\n", regval);
>  
> -	/*
> -	 * Perform a software reset to make sure the device is in a consistent
> -	 * state after start-up.
> -	 */
> -	ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
> +	/* Read shadow registers to be compared after reset */
> +	ret = regmap_bulk_read(data->regmap,
> +			       ADXL355_BASE_ADDR_SHADOW_REG,
> +			       shadow_regs, ADXL355_SHADOW_REG_COUNT);
>  	if (ret)
>  		return ret;
>  
> +	/* Do software reset and check validity of the shadow registers */
> +	while (!shadow_regs_valid && (retries > 0)) {
I would use a do { } while here.

> +		/*
> +		 * Perform a software reset to make sure the device is in a consistent
> +		 * state after start-up.
> +		 */
> +		ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
> +		if (ret)
> +			return ret;
> +
> +		/* Wait at least 5ms after software reset */
> +		usleep_range(5000, 10000);
> +
> +		/* Read shadow registers for comparison */
> +		ret = regmap_bulk_read(data->regmap,
> +				       ADXL355_BASE_ADDR_SHADOW_REG,
> +				       data->buffer.buf, ADXL355_SHADOW_REG_COUNT);
> +		if (ret)
> +			return ret;
> +
> +		/* Check if shadow registers have expected values */
> +		shadow_regs_valid = !memcmp(shadow_regs, data->buffer.buf,
> +					    ADXL355_SHADOW_REG_COUNT);
The reason for the do { } while () suggestion above is that then you can move
the memcpy into the while condition and just decrement retries unconditionally
at the top of the loop.   Then if retries is 0 in the loop exit directly.
That way we avoid need for the shadow_regs_valid variable and generally end up with
slightly shorter code.

So in all that is something like.

	do {
		retries--;
		if (!retries)
			return dev_err_probe();

		ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
		if (ret)
			return ret;

		/* Wait at least 5ms after software reset */
		usleep_range(5000, 10000);

		/* Read shadow registers for comparison */
		ret = regmap_bulk_read(data->regmap,
				       ADXL355_BASE_ADDR_SHADOW_REG,
				       data->buffer.buf, ADXL355_SHADOW_REG_COUNT);
		if (ret)
			return ret;
	} while(memcmp(shadow_regs, data->buffer.buf,
		       ADXL355_SHADOW_REG_COUNT));

> +		if (!shadow_regs_valid) {
> +			retries--;
> +			dev_warn(data->dev, "Shadow registers mismatch, retrying...\n");
I'd drop this as rather noisy. If the retry is a reasonable thing to do, we probably don't
want to bother userspace with it. If it indicates a hardware problem, just fail if
it doesn't work first time.

> +		}
> +	}
> +
> +	if (!shadow_regs_valid) {
> +		dev_err(data->dev, "Invalid shadow registers values\n");
> +		return -EIO;
> +	}
> +
>  	ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
>  				 ADXL355_POWER_CTL_DRDY_MSK,
>  				 FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1));


  reply	other threads:[~2025-09-10 18:30 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-09  8:55 [PATCH] drivers: iio: accel: fix ADX355 startup race condition Andrej Valek
2025-09-10 18:30 ` Jonathan Cameron [this message]
2025-09-11  9:33   ` Andrej Valek
2025-09-12 14:12     ` Jonathan Cameron
2025-09-15 12:03       ` Andrej Valek
2025-09-15 15:53         ` Jonathan Cameron
2025-09-16  7:07           ` Andrej Valek
2025-09-27 13:51             ` Jonathan Cameron
2025-09-29  6:10             ` Andrej Valek
2025-10-01 13:29               ` David Lechner
2025-10-01 14:42                 ` Andrej Valek
2025-09-10 18:31 ` Jonathan Cameron
2025-09-15 11:58 ` [PATCH v2] iio: accel: fix ADXL355 " Andrej Valek
2025-09-27 13:55   ` Jonathan Cameron
2025-10-01 14:37 ` [PATCH v3] " Andrej Valek
2025-10-04 15:47   ` Jonathan Cameron
2025-10-06 10:03     ` Andrej Valek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250910193049.145aa79e@jic23-huawei \
    --to=jic23@kernel.org \
    --cc=Michael.Hennerich@analog.com \
    --cc=andrej.v@skyrain.eu \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=markus.kessler@hilti.com \
    --cc=puranjay@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox