[PATCH V3 4/9] iio: imu: inv_icm42607: Add Buffer support functions to icm42607
Chris Morgan
macroalpha82 at gmail.com
Mon Mar 30 12:58:48 PDT 2026
From: Chris Morgan <macromorgan at hotmail.com>
Add all FIFO parsing and reading functions to support
inv_icm42607 hardware.
Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
drivers/iio/imu/inv_icm42607/inv_icm42607.h | 4 +
.../imu/inv_icm42607/inv_icm42607_buffer.c | 496 ++++++++++++++++++
.../imu/inv_icm42607/inv_icm42607_buffer.h | 98 ++++
.../iio/imu/inv_icm42607/inv_icm42607_core.c | 25 +
4 files changed, 623 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 7d13091aa8df..5530fd3bc03f 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -15,6 +15,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/common/inv_sensors_timestamp.h>
+#include "inv_icm42607_buffer.h"
+
enum inv_icm42607_chip {
INV_CHIP_INVALID,
INV_CHIP_ICM42607P,
@@ -137,6 +139,7 @@ struct inv_icm42607_apex {
* @indio_accel: accelerometer IIO device.
* @timestamp: interrupt timestamps.
* @apex: APEX (Advanced Pedometer and Event detection) management
+ * @fifo: FIFO management structure.
* @buffer: data transfer buffer aligned for DMA.
*/
struct inv_icm42607_state {
@@ -156,6 +159,7 @@ struct inv_icm42607_state {
s64 accel;
} timestamp;
struct inv_icm42607_apex apex;
+ struct inv_icm42607_fifo fifo;
u8 buffer[3] __aligned(IIO_DMA_MINALIGN);
};
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
new file mode 100644
index 000000000000..4f5f199586fc
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+#include <linux/iio/iio.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_buffer.h"
+
+/* FIFO header: 1 byte */
+#define INV_ICM42607_FIFO_HEADER_MSG BIT(7)
+#define INV_ICM42607_FIFO_HEADER_ACCEL BIT(6)
+#define INV_ICM42607_FIFO_HEADER_GYRO BIT(5)
+#define INV_ICM42607_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2)
+#define INV_ICM42607_FIFO_HEADER_ODR_ACCEL BIT(1)
+#define INV_ICM42607_FIFO_HEADER_ODR_GYRO BIT(0)
+
+struct inv_icm42607_fifo_1sensor_packet {
+ u8 header;
+ struct inv_icm42607_fifo_sensor_data data;
+ s8 temp;
+} __packed;
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE 8
+
+struct inv_icm42607_fifo_2sensors_packet {
+ u8 header;
+ struct inv_icm42607_fifo_sensor_data accel;
+ struct inv_icm42607_fifo_sensor_data gyro;
+ s8 temp;
+ __be16 timestamp;
+} __packed;
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE 16
+
+ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel,
+ const void **gyro, const int8_t **temp,
+ const void **timestamp, unsigned int *odr)
+{
+ const struct inv_icm42607_fifo_1sensor_packet *pack1 = packet;
+ const struct inv_icm42607_fifo_2sensors_packet *pack2 = packet;
+ u8 header = *((const u8 *)packet);
+
+ /* FIFO empty */
+ if (header & INV_ICM42607_FIFO_HEADER_MSG) {
+ *accel = NULL;
+ *gyro = NULL;
+ *temp = NULL;
+ *timestamp = NULL;
+ *odr = 0;
+ return 0;
+ }
+
+ /* handle odr flags */
+ *odr = 0;
+ if (header & INV_ICM42607_FIFO_HEADER_ODR_GYRO)
+ *odr |= INV_ICM42607_SENSOR_GYRO;
+ if (header & INV_ICM42607_FIFO_HEADER_ODR_ACCEL)
+ *odr |= INV_ICM42607_SENSOR_ACCEL;
+
+ /* accel + gyro */
+ if ((header & INV_ICM42607_FIFO_HEADER_ACCEL) &&
+ (header & INV_ICM42607_FIFO_HEADER_GYRO)) {
+ *accel = &pack2->accel;
+ *gyro = &pack2->gyro;
+ *temp = &pack2->temp;
+ *timestamp = &pack2->timestamp;
+ return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE;
+ }
+
+ /* accel only */
+ if (header & INV_ICM42607_FIFO_HEADER_ACCEL) {
+ *accel = &pack1->data;
+ *gyro = NULL;
+ *temp = &pack1->temp;
+ *timestamp = NULL;
+ return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* gyro only */
+ if (header & INV_ICM42607_FIFO_HEADER_GYRO) {
+ *accel = NULL;
+ *gyro = &pack1->data;
+ *temp = &pack1->temp;
+ *timestamp = NULL;
+ return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* invalid packet if here */
+ return -EINVAL;
+}
+
+void inv_icm42607_buffer_update_fifo_period(struct inv_icm42607_state *st)
+{
+ u32 period_gyro, period_accel;
+
+ if (st->fifo.en & INV_ICM42607_SENSOR_GYRO)
+ period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr);
+ else
+ period_gyro = U32_MAX;
+
+ if (st->fifo.en & INV_ICM42607_SENSOR_ACCEL)
+ period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr);
+ else
+ period_accel = U32_MAX;
+
+ st->fifo.period = min(period_gyro, period_accel);
+}
+
+int inv_icm42607_buffer_set_fifo_en(struct inv_icm42607_state *st,
+ unsigned int fifo_en)
+{
+ unsigned int val;
+ int ret;
+
+ /* update FIFO EN bits for accel and gyro */
+ val = 0;
+ if (fifo_en & INV_ICM42607_SENSOR_GYRO)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+ if (fifo_en & INV_ICM42607_SENSOR_ACCEL)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+ if (fifo_en & INV_ICM42607_SENSOR_TEMP)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ st->fifo.en = fifo_en;
+ inv_icm42607_buffer_update_fifo_period(st);
+
+ return 0;
+}
+
+static size_t inv_icm42607_get_packet_size(unsigned int fifo_en)
+{
+ size_t packet_size;
+
+ if ((fifo_en & INV_ICM42607_SENSOR_GYRO) &&
+ (fifo_en & INV_ICM42607_SENSOR_ACCEL))
+ packet_size = INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE;
+ else
+ packet_size = INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
+
+ return packet_size;
+}
+
+static unsigned int inv_icm42607_wm_truncate(unsigned int watermark,
+ size_t packet_size)
+{
+ size_t wm_size;
+ unsigned int wm;
+
+ wm_size = watermark * packet_size;
+ if (wm_size > INV_ICM42607_FIFO_WATERMARK_MAX)
+ wm_size = INV_ICM42607_FIFO_WATERMARK_MAX;
+
+ wm = wm_size / packet_size;
+
+ return wm;
+}
+
+/**
+ * inv_icm42607_buffer_update_watermark - update watermark FIFO threshold
+ * @st: driver internal state
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st)
+{
+ size_t packet_size, wm_size;
+ unsigned int wm_gyro, wm_accel, watermark;
+ u32 period_gyro, period_accel;
+ u32 latency_gyro, latency_accel, latency;
+ bool restore;
+ __le16 raw_wm;
+ int ret;
+
+ packet_size = inv_icm42607_get_packet_size(st->fifo.en);
+
+ /* compute sensors latency, depending on sensor watermark and odr */
+ wm_gyro = inv_icm42607_wm_truncate(st->fifo.watermark.gyro, packet_size);
+ wm_accel = inv_icm42607_wm_truncate(st->fifo.watermark.accel, packet_size);
+ /* use us for odr to avoid overflow using 32 bits values */
+ period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr) / 1000UL;
+ period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr) / 1000UL;
+ 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);
+ /* all this works because periods are multiple of each others */
+ watermark = latency / min(period_gyro, period_accel);
+ if (watermark < 1)
+ watermark = 1;
+ /* update effective watermark */
+ st->fifo.watermark.eff_gyro = latency / period_gyro;
+ if (st->fifo.watermark.eff_gyro < 1)
+ st->fifo.watermark.eff_gyro = 1;
+ st->fifo.watermark.eff_accel = latency / period_accel;
+ if (st->fifo.watermark.eff_accel < 1)
+ st->fifo.watermark.eff_accel = 1;
+ }
+
+ /* compute watermark value in bytes */
+ wm_size = watermark * packet_size;
+
+ /* changing FIFO watermark requires to turn off watermark interrupt */
+ ret = regmap_update_bits_check(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
+ 0, &restore);
+ if (ret)
+ return ret;
+
+ raw_wm = INV_ICM42607_FIFO_WATERMARK_VAL(wm_size);
+ memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
+ ret = regmap_bulk_write(st->map, INV_ICM42607_REG_FIFO_CONFIG2,
+ st->buffer, sizeof(raw_wm));
+ if (ret)
+ return ret;
+
+ /* restore watermark interrupt */
+ if (restore) {
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int inv_icm42607_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ struct inv_icm42607_sensor_state *sensor_st = iio_priv(indio_dev);
+ struct inv_sensors_timestamp *ts = &sensor_st->ts;
+
+ pm_runtime_get_sync(dev);
+
+ guard(mutex)(&st->lock);
+ inv_sensors_timestamp_reset(ts);
+
+ return 0;
+}
+
+/*
+ * update_scan_mode callback is turning sensors on and setting data FIFO enable
+ * bits.
+ */
+static int inv_icm42607_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /* exit if FIFO is already on */
+ if (st->fifo.on) {
+ st->fifo.on++;
+ return 0;
+ }
+
+ /* set FIFO threshold interrupt */
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ return ret;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ return ret;
+
+ /* set FIFO in streaming mode */
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_MODE);
+ if (ret)
+ return ret;
+
+ /* workaround: first read of FIFO count after reset is always 0 */
+ ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH, st->buffer, 2);
+ if (ret)
+ return ret;
+
+ st->fifo.on++;
+
+ return 0;
+}
+
+static int inv_icm42607_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ if (st->fifo.on > 1) {
+ st->fifo.on--;
+ return 0;
+ }
+
+ /* set FIFO in bypass mode */
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+ if (ret)
+ return ret;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ return ret;
+
+ /* disable FIFO threshold interrupt */
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
+ if (ret)
+ return ret;
+
+ st->fifo.on--;
+
+ return 0;
+}
+
+static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int sensor;
+ unsigned int *watermark;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep_sensor = 0;
+ unsigned int sleep;
+ int ret;
+
+ if (indio_dev == st->indio_gyro) {
+ sensor = INV_ICM42607_SENSOR_GYRO;
+ watermark = &st->fifo.watermark.gyro;
+ } else if (indio_dev == st->indio_accel) {
+ sensor = INV_ICM42607_SENSOR_ACCEL;
+ watermark = &st->fifo.watermark.accel;
+ } else {
+ return -EINVAL;
+ }
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42607_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
+ if (ret)
+ goto out_unlock;
+
+ *watermark = 0;
+ ret = inv_icm42607_buffer_update_watermark(st);
+ if (ret)
+ goto out_unlock;
+
+out_unlock:
+ mutex_unlock(&st->lock);
+
+ /* sleep maximum required time */
+ sleep = max(sleep_sensor, sleep_temp);
+ if (sleep)
+ msleep(sleep);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+const struct iio_buffer_setup_ops inv_icm42607_buffer_ops = {
+ .preenable = inv_icm42607_buffer_preenable,
+ .postenable = inv_icm42607_buffer_postenable,
+ .predisable = inv_icm42607_buffer_predisable,
+ .postdisable = inv_icm42607_buffer_postdisable,
+};
+
+int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st,
+ unsigned int max)
+{
+ size_t max_count;
+ __be16 *raw_fifo_count;
+ ssize_t i, size;
+ const void *accel, *gyro, *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;
+
+ /* compute maximum FIFO read size */
+ if (max == 0)
+ max_count = sizeof(st->fifo.data);
+ else
+ max_count = max * inv_icm42607_get_packet_size(st->fifo.en);
+
+ /* read FIFO count value */
+ raw_fifo_count = (__be16 *)st->buffer;
+ ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH,
+ raw_fifo_count, sizeof(*raw_fifo_count));
+ if (ret)
+ return ret;
+ st->fifo.count = be16_to_cpup(raw_fifo_count);
+
+ /* check and clamp FIFO count value */
+ if (st->fifo.count == 0)
+ return 0;
+ if (st->fifo.count > max_count)
+ st->fifo.count = max_count;
+
+ /* read all FIFO data in internal buffer */
+ ret = regmap_noinc_read(st->map, INV_ICM42607_REG_FIFO_DATA,
+ st->fifo.data, st->fifo.count);
+ if (ret)
+ return ret;
+
+ /* compute number of samples for each sensor */
+ for (i = 0; i < st->fifo.count; i += size) {
+ size = inv_icm42607_fifo_decode_packet(&st->fifo.data[i],
+ &accel, &gyro, &temp, ×tamp, &odr);
+ if (size <= 0)
+ break;
+ if (gyro != NULL && inv_icm42607_fifo_is_data_valid(gyro))
+ st->fifo.nb.gyro++;
+ if (accel != NULL && inv_icm42607_fifo_is_data_valid(accel))
+ st->fifo.nb.accel++;
+ st->fifo.nb.total++;
+ }
+
+ return 0;
+}
+
+int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,
+ unsigned int count)
+{
+ s64 gyro_ts, accel_ts;
+ int ret;
+
+ gyro_ts = iio_get_time_ns(st->indio_gyro);
+ accel_ts = iio_get_time_ns(st->indio_accel);
+
+ ret = inv_icm42607_buffer_fifo_read(st, count);
+
+ return ret;
+}
+
+int inv_icm42607_buffer_init(struct inv_icm42607_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ st->fifo.watermark.eff_gyro = 1;
+ st->fifo.watermark.eff_accel = 1;
+
+ /* Configure FIFO_COUNT format in bytes and big endian */
+ val = INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN;
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ val, val);
+ if (ret)
+ return ret;
+
+ /* Initialize FIFO in bypass mode */
+ return regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
new file mode 100644
index 000000000000..64a66c00a861
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_BUFFER_H_
+#define INV_ICM42607_BUFFER_H_
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+struct inv_icm42607_state;
+
+#define INV_ICM42607_SENSOR_GYRO BIT(0)
+#define INV_ICM42607_SENSOR_ACCEL BIT(1)
+#define INV_ICM42607_SENSOR_TEMP BIT(2)
+
+/**
+ * struct inv_icm42607_fifo - FIFO state variables
+ * @on: reference counter for FIFO on.
+ * @en: bits field of INV_ICM42607_SENSOR_* for FIFO EN bits.
+ * @period: FIFO internal period.
+ * @watermark: watermark configuration values for accel and gyro.
+ * @count: number of bytes in the FIFO data buffer.
+ * @nb: gyro, accel and total samples in the FIFO data buffer.
+ * @data: FIFO data buffer aligned for DMA (2kB + 32 bytes of read cache).
+ */
+struct inv_icm42607_fifo {
+ unsigned int on;
+ unsigned int en;
+ u32 period;
+ struct {
+ unsigned int gyro;
+ unsigned int accel;
+ unsigned int eff_gyro;
+ unsigned int eff_accel;
+ } watermark;
+ size_t count;
+ struct {
+ size_t gyro;
+ size_t accel;
+ size_t total;
+ } nb;
+ u8 data[2080] __aligned(IIO_DMA_MINALIGN);
+};
+
+/* FIFO data packet */
+struct inv_icm42607_fifo_sensor_data {
+ __be16 x;
+ __be16 y;
+ __be16 z;
+} __packed;
+#define INV_ICM42607_FIFO_DATA_INVALID -32768
+
+static inline s16 inv_icm42607_fifo_get_sensor_data(__be16 d)
+{
+ return be16_to_cpu(d);
+}
+
+static inline bool
+inv_icm42607_fifo_is_data_valid(const struct inv_icm42607_fifo_sensor_data *s)
+{
+ s16 x, y, z;
+
+ x = inv_icm42607_fifo_get_sensor_data(s->x);
+ y = inv_icm42607_fifo_get_sensor_data(s->y);
+ z = inv_icm42607_fifo_get_sensor_data(s->z);
+
+ if (x == INV_ICM42607_FIFO_DATA_INVALID &&
+ y == INV_ICM42607_FIFO_DATA_INVALID &&
+ z == INV_ICM42607_FIFO_DATA_INVALID)
+ return false;
+
+ return true;
+}
+
+ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel,
+ const void **gyro, const s8 **temp,
+ const void **timestamp, unsigned int *odr);
+
+extern const struct iio_buffer_setup_ops inv_icm42607_buffer_ops;
+
+int inv_icm42607_buffer_init(struct inv_icm42607_state *st);
+
+void inv_icm42607_buffer_update_fifo_period(struct inv_icm42607_state *st);
+
+int inv_icm42607_buffer_set_fifo_en(struct inv_icm42607_state *st,
+ unsigned int fifo_en);
+
+int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st);
+
+int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st,
+ unsigned int max);
+
+int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,
+ unsigned int count);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index da04c820dab2..344071089042 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -18,6 +18,7 @@
#include <linux/iio/iio.h>
#include "inv_icm42607.h"
+#include "inv_icm42607_buffer.h"
static const struct regmap_range_cfg inv_icm42607_regmap_ranges[] = {
{
@@ -373,6 +374,11 @@ int inv_icm42607_core_probe(struct regmap *regmap, int chip,
if (ret)
return ret; /* Return error from setup (e.g., WHOAMI fail) */
+ /* Initialize buffer/FIFO handling */
+ ret = inv_icm42607_buffer_init(st);
+ if (ret)
+ return ret;
+
/* Setup runtime power management */
ret = devm_pm_runtime_set_active_enabled(dev);
if (ret)
@@ -405,6 +411,13 @@ static int inv_icm42607_suspend(struct device *dev)
if (pm_runtime_suspended(dev))
return 0;
+ if (st->fifo.on) {
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+ if (ret)
+ return ret;
+ }
+
/* keep chip on and wake-up capable if APEX and wakeup on */
accel_dev = &st->indio_accel->dev;
wakeup = st->apex.on && device_may_wakeup(accel_dev);
@@ -436,6 +449,8 @@ static int inv_icm42607_suspend(struct device *dev)
static int inv_icm42607_resume(struct device *dev)
{
struct inv_icm42607_state *st = dev_get_drvdata(dev);
+ struct inv_icm42607_sensor_state *gyro_st = iio_priv(st->indio_gyro);
+ struct inv_icm42607_sensor_state *accel_st = iio_priv(st->indio_accel);
struct device *accel_dev;
bool wakeup;
int ret;
@@ -462,6 +477,16 @@ static int inv_icm42607_resume(struct device *dev)
ret = inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
st->suspended.accel,
st->suspended.temp, NULL);
+ if (ret)
+ return ret;
+
+ if (st->fifo.on) {
+ inv_sensors_timestamp_reset(&gyro_st->ts);
+ inv_sensors_timestamp_reset(&accel_st->ts);
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_MODE);
+ }
+
return ret;
}
--
2.43.0
More information about the Linux-rockchip
mailing list