From 0a4d86c557edcbc53bb861416ed0cf1f9a99c6c7 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Tue, 15 Apr 2025 15:09:44 -0400 Subject: [PATCH] sensor: icm45686: Add I2C bus support Validated for read/decode APIs, as well as Streaming mode (FIFO). Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm45686/Kconfig | 6 ++-- drivers/sensor/tdk/icm45686/icm45686.c | 34 ++++++++++++++++--- drivers/sensor/tdk/icm45686/icm45686.h | 6 ++++ drivers/sensor/tdk/icm45686/icm45686_bus.h | 6 ++++ drivers/sensor/tdk/icm45686/icm45686_stream.c | 19 +++++++++++ .../sensor/invensense,icm45686-i2c.yaml | 30 ++++++++++++++++ 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 dts/bindings/sensor/invensense,icm45686-i2c.yaml diff --git a/drivers/sensor/tdk/icm45686/Kconfig b/drivers/sensor/tdk/icm45686/Kconfig index 14fa7a6e9e3..46c4cb4f25d 100644 --- a/drivers/sensor/tdk/icm45686/Kconfig +++ b/drivers/sensor/tdk/icm45686/Kconfig @@ -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. diff --git a/drivers/sensor/tdk/icm45686/icm45686.c b/drivers/sensor/tdk/icm45686/icm45686.c index 70a971d8b28..c9be2f87673 100644 --- a/drivers/sensor/tdk/icm45686/icm45686.c +++ b/drivers/sensor/tdk/icm45686/icm45686.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -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), ()) \ }, \ }; \ \ diff --git a/drivers/sensor/tdk/icm45686/icm45686.h b/drivers/sensor/tdk/icm45686/icm45686.h index 3fcf86c025e..3e37e5cbcfb 100644 --- a/drivers/sensor/tdk/icm45686/icm45686.h +++ b/drivers/sensor/tdk/icm45686/icm45686.h @@ -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; diff --git a/drivers/sensor/tdk/icm45686/icm45686_bus.h b/drivers/sensor/tdk/icm45686/icm45686_bus.h index 0ba0b62019b..22d0ccb40e4 100644 --- a/drivers/sensor/tdk/icm45686/icm45686_bus.h +++ b/drivers/sensor/tdk/icm45686/icm45686_bus.h @@ -36,6 +36,9 @@ static inline int icm45686_bus_read(const struct device *dev, rtio_sqe_prep_write(write_sqe, iodev, RTIO_PRIO_HIGH, ®, 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, ®, 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) { diff --git a/drivers/sensor/tdk/icm45686/icm45686_stream.c b/drivers/sensor/tdk/icm45686/icm45686_stream.c index 493f9a4132e..348c5b36966 100644 --- a/drivers/sensor/tdk/icm45686/icm45686_stream.c +++ b/drivers/sensor/tdk/icm45686/icm45686_stream.c @@ -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, diff --git a/dts/bindings/sensor/invensense,icm45686-i2c.yaml b/dts/bindings/sensor/invensense,icm45686-i2c.yaml new file mode 100644 index 00000000000..778e4a47c09 --- /dev/null +++ b/dts/bindings/sensor/invensense,icm45686-i2c.yaml @@ -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 + + &i2c0 { + ... + + icm42688: icm45686@68 { + ... + + accel-pwr-mode = ; + accel-fs = ; + accel-odr = ; + gyro-pwr-mode= ; + gyro-fs = ; + gyro-odr = ; + }; + }; + +compatible: "invensense,icm45686" + +include: ["i2c-device.yaml", "invensense,icm45686-common.yaml"]