sensor: icm45686: Add I2C bus support

Validated for read/decode APIs, as well as Streaming mode (FIFO).

Signed-off-by: Luis Ubieda <luisf@croxel.com>
This commit is contained in:
Luis Ubieda 2025-04-15 15:09:44 -04:00 committed by Benjamin Cabé
commit 0a4d86c557
6 changed files with 94 additions and 7 deletions

View file

@ -6,8 +6,10 @@ menuconfig ICM45686
bool "ICM45686 High-precision 6-Axis Motion Tracking Device"
default y
depends on DT_HAS_INVENSENSE_ICM45686_ENABLED
select SPI
select SPI_RTIO
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM45686),spi)
select SPI_RTIO if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM45686),spi)
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM45686),i2c)
select I2C_RTIO if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM45686),i2c)
help
Enable driver for ICM45686 High-precision 6-axis motion
tracking device.

View file

@ -10,6 +10,7 @@
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/rtio/rtio.h>
@ -199,6 +200,9 @@ static inline void icm45686_submit_one_shot(const struct device *dev,
edata->payload.buf,
sizeof(edata->payload.buf),
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
read_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
read_sqe->flags |= RTIO_SQE_CHAINED;
rtio_sqe_prep_callback_no_cqe(complete_sqe,
@ -245,10 +249,18 @@ static int icm45686_init(const struct device *dev)
uint8_t val;
int err;
if (!spi_is_ready_iodev(data->rtio.iodev)) {
#if CONFIG_SPI_RTIO
if ((data->rtio.type == ICM45686_BUS_SPI) && !spi_is_ready_iodev(data->rtio.iodev)) {
LOG_ERR("Bus is not ready");
return -ENODEV;
}
#endif
#if CONFIG_I2C_RTIO
if ((data->rtio.type == ICM45686_BUS_I2C) && !i2c_is_ready_iodev(data->rtio.iodev)) {
LOG_ERR("Bus is not ready");
return -ENODEV;
}
#endif
/* Soft-reset sensor to restore config to defaults */
@ -383,10 +395,18 @@ static int icm45686_init(const struct device *dev)
#define ICM45686_INIT(inst) \
\
RTIO_DEFINE(icm45686_rtio_ctx_##inst, 8, 8); \
SPI_DT_IODEV_DEFINE(icm45686_bus_##inst, \
DT_DRV_INST(inst), \
SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB, \
0U); \
\
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(SPI_DT_IODEV_DEFINE(icm45686_bus_##inst, \
DT_DRV_INST(inst), \
SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB, \
0U)), \
()); \
\
COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \
(I2C_DT_IODEV_DEFINE(icm45686_bus_##inst, \
DT_DRV_INST(inst))), \
()); \
\
static const struct icm45686_config icm45686_cfg_##inst = { \
.settings = { \
@ -414,6 +434,10 @@ static int icm45686_init(const struct device *dev)
.rtio = { \
.iodev = &icm45686_bus_##inst, \
.ctx = &icm45686_rtio_ctx_##inst, \
COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \
(.type = ICM45686_BUS_I2C), ()) \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(.type = ICM45686_BUS_SPI), ()) \
}, \
}; \
\

View file

@ -130,10 +130,16 @@ struct icm45686_stream {
} data;
};
enum icm45686_bus_type {
ICM45686_BUS_SPI,
ICM45686_BUS_I2C,
};
struct icm45686_data {
struct {
struct rtio_iodev *iodev;
struct rtio *ctx;
enum icm45686_bus_type type;
} rtio;
/** Single-shot encoded data instance to support fetch/get API */
struct icm45686_encoded_data edata;

View file

@ -36,6 +36,9 @@ static inline int icm45686_bus_read(const struct device *dev,
rtio_sqe_prep_write(write_sqe, iodev, RTIO_PRIO_HIGH, &reg, 1, NULL);
write_sqe->flags |= RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_sqe, iodev, RTIO_PRIO_HIGH, buf, len, NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
read_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
err = rtio_submit(ctx, 2);
if (err) {
@ -73,6 +76,9 @@ static inline int icm45686_bus_write(const struct device *dev,
rtio_sqe_prep_write(write_reg_sqe, iodev, RTIO_PRIO_HIGH, &reg, 1, NULL);
write_reg_sqe->flags |= RTIO_SQE_TRANSACTION;
rtio_sqe_prep_write(write_buf_sqe, iodev, RTIO_PRIO_HIGH, buf, len, NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
write_buf_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP;
}
err = rtio_submit(ctx, 2);
if (err) {

View file

@ -204,6 +204,9 @@ static void icm45686_handle_event_actions(struct rtio *ctx,
(buf->header.fifo_count *
sizeof(struct icm45686_encoded_fifo_payload)),
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
data_rd_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
data_rd_sqe->flags |= RTIO_SQE_CHAINED;
} else if (should_flush_fifo(read_cfg, int_status)) {
@ -232,6 +235,9 @@ static void icm45686_handle_event_actions(struct rtio *ctx,
write_reg,
sizeof(write_reg),
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
write_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP;
}
write_sqe->flags |= RTIO_SQE_CHAINED;
} else if (should_read_data(read_cfg, int_status)) {
@ -269,6 +275,9 @@ static void icm45686_handle_event_actions(struct rtio *ctx,
buf->payload.buf,
sizeof(buf->payload.buf),
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
read_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
read_sqe->flags |= RTIO_SQE_CHAINED;
}
@ -318,6 +327,9 @@ static void icm45686_event_handler(const struct device *dev)
wr_data,
sizeof(wr_data),
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
write_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP;
}
rtio_submit(data->rtio.ctx, 0);
data->stream.settings.enabled.drdy = false;
@ -375,8 +387,12 @@ static void icm45686_event_handler(const struct device *dev)
&data->stream.data.int_status,
1,
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
read_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
read_sqe->flags |= RTIO_SQE_CHAINED;
/** Preemptively read FIFO count so we can decide on the next callback
* how much FIFO data we'd read (if needed).
*/
@ -395,6 +411,9 @@ static void icm45686_event_handler(const struct device *dev)
(uint8_t *)&data->stream.data.fifo_count,
2,
NULL);
if (data->rtio.type == ICM45686_BUS_I2C) {
read_fifo_ct_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
read_fifo_ct_sqe->flags |= RTIO_SQE_CHAINED;
rtio_sqe_prep_callback_no_cqe(complete_sqe,

View file

@ -0,0 +1,30 @@
# Copyright (c) 2025 Croxel Inc.
# SPDX-License-Identifier: Apache-2.0
description: |
ICM45686 High-precision 6-axis motion tracking device
When setting the accel-pm, accel-range, accel-odr, gyro-pm, gyro-range,
gyro-odr properties in a .dts or .dtsi file you may include icm45686.h
and use the macros defined there.
Example:
#include <zephyr/dt-bindings/sensor/icm45686.h>
&i2c0 {
...
icm42688: icm45686@68 {
...
accel-pwr-mode = <ICM45686_DT_ACCEL_LN>;
accel-fs = <ICM45686_DT_ACCEL_FS_32>;
accel-odr = <ICM45686_DT_ACCEL_ODR_800>;
gyro-pwr-mode= <ICM45686_DT_GYRO_LN>;
gyro-fs = <ICM45686_DT_GYRO_FS_4000>;
gyro-odr = <ICM45686_DT_GYRO_ODR_800>;
};
};
compatible: "invensense,icm45686"
include: ["i2c-device.yaml", "invensense,icm45686-common.yaml"]