All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Shevchenko <andriy.shevchenko@intel.com>
To: remi.buisson@tdk.com
Cc: "Jonathan Cameron" <jic23@kernel.org>,
	"David Lechner" <dlechner@baylibre.com>,
	"Nuno Sá" <nuno.sa@analog.com>,
	"Andy Shevchenko" <andy@kernel.org>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org,
	devicetree@vger.kernel.org
Subject: Re: [PATCH v5 3/9] iio: imu: inv_icm45600: add buffer support in iio devices
Date: Thu, 21 Aug 2025 12:20:53 +0300	[thread overview]
Message-ID: <aKbk9WYtfb5L5la4@smile.fi.intel.com> (raw)
In-Reply-To: <20250820-add_newport_driver-v5-3-2fc9f13dddee@tdk.com>

On Wed, Aug 20, 2025 at 02:24:21PM +0000, Remi Buisson via B4 Relay wrote:
> 
> Add FIFO control functions.
> Support hwfifo watermark by multiplexing gyro and accel settings.
> Support hwfifo flush.

...

> +#define INV_ICM45600_SENSOR_CONF_KEEP_VALUES {U8_MAX, U8_MAX, U8_MAX, U8_MAX, }

When one line, no need to have inner trailing comma, besides that missed space.

...

> +{
> +	unsigned int mask, val;
> +	int ret;
> +
> +	/* Update only FIFO EN bits. */
> +	mask = INV_ICM45600_FIFO_CONFIG3_GYRO_EN |
> +	       INV_ICM45600_FIFO_CONFIG3_ACCEL_EN;

> +	val = 0;

Why not to put it under else branch?

> +	if ((fifo_en & INV_ICM45600_SENSOR_GYRO) || (fifo_en & INV_ICM45600_SENSOR_ACCEL))
> +		val = (INV_ICM45600_FIFO_CONFIG3_GYRO_EN | INV_ICM45600_FIFO_CONFIG3_ACCEL_EN);
> +
> +	ret = regmap_update_bits(st->map, INV_ICM45600_REG_FIFO_CONFIG3, mask, val);
> +	if (ret)
> +		return ret;
> +
> +	st->fifo.en = fifo_en;
> +	inv_icm45600_buffer_update_fifo_period(st);
> +
> +	return 0;
> +}

...

> +static unsigned int inv_icm45600_wm_truncate(unsigned int watermark, size_t packet_size,
> +					     unsigned int fifo_period)
> +{
> +	size_t watermark_max, grace_samples;
> +
> +	/* Keep 20ms for processing FIFO. fifo_period is in ns */
> +	grace_samples = (20U * 1000000U) / fifo_period;

We have NSEC_PER_MSEC, other similar constants, check respective time.h and units.h.

> +	if (grace_samples < 1)
> +		grace_samples = 1;
> +
> +	watermark_max = INV_ICM45600_FIFO_SIZE_MAX / packet_size;
> +	watermark_max -= grace_samples;
> +
> +	return min(watermark, watermark_max);

Where is the header for min()?

> +}

...

> +/**
> + * inv_icm45600_buffer_update_watermark - update watermark FIFO threshold
> + * @st:	driver internal state

> + * Returns 0 on success, a negative error code otherwise.

Return section is missed and has to be the last one. Please, read how to create
proper kernel-doc.

> + * FIFO watermark threshold is computed based on the required watermark values
> + * set for gyro and accel sensors. Since watermark is all about acceptable data
> + * latency, use the smallest setting between the 2. It means choosing the
> + * smallest latency but this is not as simple as choosing the smallest watermark
> + * value. Latency depends on watermark and ODR. It requires several steps:
> + * 1) compute gyro and accel latencies and choose the smallest value.
> + * 2) adapt the chosen latency so that it is a multiple of both gyro and accel
> + *    ones. Otherwise it is possible that you don't meet a requirement. (for
> + *    example with gyro @100Hz wm 4 and accel @100Hz with wm 6, choosing the
> + *    value of 4 will not meet accel latency requirement because 6 is not a
> + *    multiple of 4. You need to use the value 2.)
> + * 3) Since all periods are multiple of each others, watermark is computed by
> + *    dividing this computed latency by the smallest period, which corresponds
> + *    to the FIFO frequency.
> + */
> +int inv_icm45600_buffer_update_watermark(struct inv_icm45600_state *st)
> +{
> +	const size_t packet_size = sizeof(struct inv_icm45600_fifo_2sensors_packet);
> +	unsigned int wm_gyro, wm_accel, watermark;
> +	u32 period_gyro, period_accel, period;
> +	u32 latency_gyro, latency_accel, latency;
> +
> +	/* Compute sensors latency, depending on sensor watermark and odr. */
> +	wm_gyro = inv_icm45600_wm_truncate(st->fifo.watermark.gyro, packet_size,
> +					   st->fifo.period);
> +	wm_accel = inv_icm45600_wm_truncate(st->fifo.watermark.accel, packet_size,
> +					    st->fifo.period);
> +	/* Use us for odr to avoid overflow using 32 bits values. */
> +	period_gyro = inv_icm45600_odr_to_period(st->conf.gyro.odr) / 1000UL;
> +	period_accel = inv_icm45600_odr_to_period(st->conf.accel.odr) / 1000UL;

Replace 1000UL by the respective predefined constants.

> +	latency_gyro = period_gyro * wm_gyro;
> +	latency_accel = period_accel * wm_accel;
> +
> +	/* 0 value for watermark means that the sensor is turned off. */
> +	if (wm_gyro == 0 && wm_accel == 0)
> +		return 0;
> +
> +	if (latency_gyro == 0) {
> +		watermark = wm_accel;
> +		st->fifo.watermark.eff_accel = wm_accel;
> +	} else if (latency_accel == 0) {
> +		watermark = wm_gyro;
> +		st->fifo.watermark.eff_gyro = wm_gyro;
> +	} else {
> +		/* Compute the smallest latency that is a multiple of both. */
> +		if (latency_gyro <= latency_accel)
> +			latency = latency_gyro - (latency_accel % latency_gyro);
> +		else
> +			latency = latency_accel - (latency_gyro % latency_accel);
> +		/* Use the shortest period. */
> +		period = min(period_gyro, period_accel);
> +		/* All this works because periods are multiple of each others. */
> +		watermark = max(latency / period, 1);
> +		/* Update effective watermark. */
> +		st->fifo.watermark.eff_gyro = max(latency / period_gyro, 1);
> +		st->fifo.watermark.eff_accel = max(latency / period_accel, 1);
> +	}
> +
> +

One blank line is enough.

> +	st->buffer.u16 = cpu_to_le16(watermark);
> +	return regmap_bulk_write(st->map, INV_ICM45600_REG_FIFO_WATERMARK,
> +				 &st->buffer.u16, sizeof(st->buffer.u16));
> +}

...

...

> +	if (sensor == INV_ICM45600_SENSOR_GYRO)
> +		ret = inv_icm45600_set_gyro_conf(st, &conf, sleep);
> +	else
> +		ret = inv_icm45600_set_accel_conf(st, &conf, sleep);
> +
> +	return ret;

Just return directly in the branches.

...

> +int inv_icm45600_buffer_fifo_read(struct inv_icm45600_state *st)
> +{
> +	const ssize_t packet_size = sizeof(struct inv_icm45600_fifo_2sensors_packet);
> +	__le16 *raw_fifo_count;
> +	size_t fifo_nb, i;
> +	ssize_t size;
> +	const struct inv_icm45600_fifo_sensor_data *accel, *gyro;
> +	const __le16 *timestamp;
> +	const s8 *temp;
> +	unsigned int odr;
> +	int ret;
> +
> +	/* Reset all samples counters. */
> +	st->fifo.count = 0;
> +	st->fifo.nb.gyro = 0;
> +	st->fifo.nb.accel = 0;
> +	st->fifo.nb.total = 0;
> +
> +	/* Read FIFO count value. */
> +	raw_fifo_count = &st->buffer.u16;
> +	ret = regmap_bulk_read(st->map, INV_ICM45600_REG_FIFO_COUNT,
> +			       raw_fifo_count, sizeof(*raw_fifo_count));
> +	if (ret)
> +		return ret;

+ blank line

> +	fifo_nb = le16_to_cpup(raw_fifo_count);
> +
> +	/* Check and limit number of samples if requested. */
> +	if (fifo_nb == 0)
> +		return 0;

Better to reformat as

	/* Check and limit number of samples if requested. */
	fifo_nb = le16_to_cpup(raw_fifo_count);
	if (fifo_nb == 0)
		return 0;

> +	/* Try to read all FIFO data in internal buffer. */
> +	st->fifo.count = fifo_nb * packet_size;
> +	ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA,
> +				st->fifo.data, st->fifo.count);
> +	if (ret == -ENOTSUPP || ret == -EFBIG) {

Strictly speaking this is a bit of layering issue, do we have other means to
check the support before even trying?

> +		/* Read full fifo is not supported, read samples one by one. */
> +		ret = 0;
> +		for (i = 0; i < st->fifo.count && ret == 0; i += packet_size)
> +			ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA,
> +						&st->fifo.data[i], packet_size);
> +	}
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < st->fifo.count; i += size) {
> +		size = inv_icm45600_fifo_decode_packet(&st->fifo.data[i], &accel, &gyro,
> +						       &temp, &timestamp, &odr);
> +		if (size <= 0)

Doesn't size < 0 is an error condition that should be returned?

> +			break;
> +		if (gyro != NULL && inv_icm45600_fifo_is_data_valid(gyro))
> +			st->fifo.nb.gyro++;
> +		if (accel != NULL && inv_icm45600_fifo_is_data_valid(accel))
> +			st->fifo.nb.accel++;

Drop ' != NULL' parts.

> +		st->fifo.nb.total++;
> +	}
> +
> +	return 0;
> +}

...

> +int inv_icm45600_buffer_init(struct inv_icm45600_state *st)
> +{
> +	int ret;
> +	unsigned int val;
> +
> +	st->fifo.watermark.eff_gyro = 1;
> +	st->fifo.watermark.eff_accel = 1;
> +
> +	/* Disable all FIFO EN bits. */
> +	ret = regmap_write(st->map, INV_ICM45600_REG_FIFO_CONFIG3, 0);
> +	if (ret)
> +		return ret;
> +
> +	/* Disable FIFO and set depth. */
> +	val = FIELD_PREP(INV_ICM45600_FIFO_CONFIG0_MODE_MASK,
> +			 INV_ICM45600_FIFO_CONFIG0_MODE_BYPASS);
> +	val |= INV_ICM45600_FIFO_CONFIG0_FIFO_DEPTH_MAX;

FIELD_MODIFY()

> +	ret = regmap_write(st->map, INV_ICM45600_REG_FIFO_CONFIG0, val);
> +	if (ret)
> +		return ret;
> +
> +	/* Enable only timestamp in fifo, disable compression. */
> +	ret = regmap_write(st->map, INV_ICM45600_REG_FIFO_CONFIG4,
> +			   INV_ICM45600_FIFO_CONFIG4_TMST_FSYNC_EN);
> +	if (ret)
> +		return ret;
> +
> +	/* Enable FIFO continuous watermark interrupt. */
> +	return regmap_set_bits(st->map, INV_ICM45600_REG_FIFO_CONFIG2,
> +			       INV_ICM45600_REG_FIFO_CONFIG2_WM_GT_TH);
> +}

...

> +#ifndef INV_ICM45600_BUFFER_H_
> +#define INV_ICM45600_BUFFER_H_
> +
> +#include <linux/bits.h>
> +#include <linux/iio/iio.h>
> +#include <linux/types.h>

IWYU, please.

...

> +/* FIFO data packet */
> +struct inv_icm45600_fifo_sensor_data {
> +	__le16 x;
> +	__le16 y;
> +	__le16 z;
> +} __packed;

Why __packed? Do you expect this to be on unaligned addresses?

...

> +#define INV_ICM45600_DATA_INVALID		S16_MIN

limits.h?

...

> +static inline s16 inv_icm45600_fifo_get_sensor_data(__le16 d)
> +{
> +	return le16_to_cpu(d);

asm/byteorder.h ?

> +}

...

> +static inline bool
> +inv_icm45600_fifo_is_data_valid(const struct inv_icm45600_fifo_sensor_data *s)
> +{
> +	s16 x, y, z;
> +
> +	x = inv_icm45600_fifo_get_sensor_data(s->x);
> +	y = inv_icm45600_fifo_get_sensor_data(s->y);
> +	z = inv_icm45600_fifo_get_sensor_data(s->z);
> +
> +	if (x == INV_ICM45600_DATA_INVALID &&
> +	    y == INV_ICM45600_DATA_INVALID &&
> +	    z == INV_ICM45600_DATA_INVALID)
> +		return false;
> +
> +	return true;

'if' can be avoided. But it's up to you. All depends on the readability of the
end result.

> +}

...

> +/**
> + * inv_icm45600_irq_init() - initialize int pin and interrupt handler
> + * @st:		driver internal state
> + * @irq:	irq number
> + * @irq_type:	irq trigger type
> + * @open_drain:	true if irq is open drain, false for push-pull
> + *
> + * Returns 0 on success, a negative error code otherwise.

kernel-doc validation...

> + */

...

> +	st->fifo.data = devm_kzalloc(dev, 8192, GFP_KERNEL);
> +	if (!st->fifo.data)
> +		return dev_err_probe(dev, -ENOMEM, "Cannot allocate fifo memory\n");

HAve you checked what will happen in this case? Please, take a look and update
the code accordingly.

...

> -	scoped_guard(mutex, &st->lock)
> +	scoped_guard(mutex, &st->lock) {

Ah, nice. It should have been done in the first place and put a comment to that
patch that scoped_guard() {} used specifically for limiting churn in the next
changes.

>  		/* Restore sensors state. */
>  		ret = inv_icm45600_set_pwr_mgmt0(st, st->suspended.gyro,

> -						st->suspended.accel, NULL);
> +						 st->suspended.accel, NULL);

Stray change.

> +		if (ret)
> +			return ret;
> +
> +		/* Restore FIFO data streaming. */
> +		if (st->fifo.on) {
> +			struct inv_icm45600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
> +			struct inv_icm45600_sensor_state *accel_st = iio_priv(st->indio_accel);
> +			unsigned int val;
> +
> +			inv_sensors_timestamp_reset(&gyro_st->ts);
> +			inv_sensors_timestamp_reset(&accel_st->ts);
> +			val = FIELD_PREP(INV_ICM45600_FIFO_CONFIG0_MODE_MASK,
> +					 INV_ICM45600_FIFO_CONFIG0_MODE_STREAM);
> +			ret = regmap_update_bits(st->map, INV_ICM45600_REG_FIFO_CONFIG0,
> +						 INV_ICM45600_FIFO_CONFIG0_MODE_MASK, val);
> +			if (ret)
> +				return ret;
> +			/* FIFO_CONFIG3_IF_EN must only be set at end of FIFO the configuration */
> +			ret = regmap_set_bits(st->map, INV_ICM45600_REG_FIFO_CONFIG3,
> +					      INV_ICM45600_FIFO_CONFIG3_IF_EN);

This relies on the code elsewhere, much better to return here if an error
condition happened.

> +		}
> +	}

-- 
With Best Regards,
Andy Shevchenko



  reply	other threads:[~2025-08-21  9:20 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-20 14:24 [PATCH v5 0/9] iio: imu: new inv_icm45600 driver Remi Buisson
2025-08-20 14:24 ` Remi Buisson via B4 Relay
2025-08-20 14:24 ` [PATCH v5 1/9] dt-bindings: iio: imu: Add inv_icm45600 Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-20 19:33   ` Conor Dooley
2025-08-20 14:24 ` [PATCH v5 2/9] iio: imu: inv_icm45600: add new inv_icm45600 driver Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-21  9:02   ` Andy Shevchenko
2025-09-04 12:58     ` Remi Buisson
2025-09-04 13:17       ` Andy Shevchenko
2025-09-05 12:43         ` Remi Buisson
2025-09-05 13:47           ` Andy Shevchenko
2025-08-25 10:34   ` Jonathan Cameron
2025-09-04 13:04     ` Remi Buisson
2025-09-07 13:31       ` Jonathan Cameron
2025-08-20 14:24 ` [PATCH v5 3/9] iio: imu: inv_icm45600: add buffer support in iio devices Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-21  9:20   ` Andy Shevchenko [this message]
2025-09-04 13:01     ` Remi Buisson
2025-09-04 13:49       ` Andy Shevchenko
2025-09-05 12:44         ` Remi Buisson
2025-09-05 13:49           ` Andy Shevchenko
2025-09-07 13:34           ` Jonathan Cameron
2025-09-22  8:52           ` Remi Buisson
2025-08-25 10:42   ` Jonathan Cameron
2025-09-04 13:05     ` Remi Buisson
2025-08-20 14:24 ` [PATCH v5 4/9] iio: imu: inv_icm45600: add IMU IIO gyroscope device Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-25 10:55   ` Jonathan Cameron
2025-09-04 13:06     ` Remi Buisson
2025-08-20 14:24 ` [PATCH v5 5/9] iio: imu: inv_icm45600: add IMU IIO accelerometer device Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-20 14:24 ` [PATCH v5 6/9] iio: imu: inv_icm45600: add I2C driver for inv_icm45600 driver Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-20 14:24 ` [PATCH v5 7/9] iio: imu: inv_icm45600: add SPI " Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-20 14:24 ` [PATCH v5 8/9] iio: imu: inv_icm45600: add I3C " Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay
2025-08-20 14:24 ` [PATCH v5 9/9] MAINTAINERS: add entry for inv_icm45600 6-axis imu sensor Remi Buisson
2025-08-20 14:24   ` Remi Buisson via B4 Relay

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=aKbk9WYtfb5L5la4@smile.fi.intel.com \
    --to=andriy.shevchenko@intel.com \
    --cc=andy@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=jic23@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nuno.sa@analog.com \
    --cc=remi.buisson@tdk.com \
    --cc=robh@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.