diff --git a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts index 04d513d2eca32..498c4a02ede36 100644 --- a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts +++ b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts @@ -241,23 +241,33 @@ }; }; -#include +#include &lpspi1 { status = "okay"; cs-gpios =<&gpio2 11 GPIO_ACTIVE_LOW>; - icm42688_0: icm42688p0@0 { - compatible = "invensense,icm42688"; + icm42686: icm42686p@0 { + compatible = "invensense,icm42686"; reg = <0>; - int-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + int-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + int1-mode = ; + int1-pol = ; + fifo-ths-int-clr = ; + fifo-full-int-clr = ; + fifo-mode = ; + tmst-delta-en; + tmst-regs-en; + tmst-res = ; spi-max-frequency = <24000000>; - accel-pwr-mode = ; - accel-odr = ; - accel-fs = ; - gyro-pwr-mode = ; - gyro-odr = ; - gyro-fs = ; + accel-pwr-mode = ; + accel-odr = ; + accel-fs = ; + accel-aaf-bw = ; + gyro-pwr-mode = ; + gyro-odr = ; + gyro-fs = ; + gyro-aaf-bw = ; }; }; @@ -265,17 +275,27 @@ status = "okay"; cs-gpios =<&gpio3 24 GPIO_ACTIVE_LOW>; - icm42688_1: icm42688p1@0 { + icm42688: icm42688p@0 { compatible = "invensense,icm42688"; reg = <0>; - int-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; + int-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; + int1-mode = ; + int1-pol = ; + fifo-ths-int-clr = ; + fifo-full-int-clr = ; + fifo-mode = ; + tmst-delta-en; + tmst-regs-en; + tmst-res = ; spi-max-frequency = <24000000>; - accel-pwr-mode = ; - accel-odr = ; + accel-pwr-mode = ; + accel-odr = ; accel-fs = ; - gyro-pwr-mode = ; - gyro-odr = ; + accel-aaf-bw = ; + gyro-pwr-mode = ; + gyro-odr = ; gyro-fs = ; + gyro-aaf-bw = ; }; }; diff --git a/boards/tdk/robokit1/robokit1-common.dtsi b/boards/tdk/robokit1/robokit1-common.dtsi index 69c032974b895..965c8fde11537 100644 --- a/boards/tdk/robokit1/robokit1-common.dtsi +++ b/boards/tdk/robokit1/robokit1-common.dtsi @@ -89,7 +89,7 @@ }; }; -#include +#include &spi0 { pinctrl-0 = <&spi0_default>; @@ -105,12 +105,14 @@ reg = <0>; int-gpios = <&pioc 5 GPIO_ACTIVE_HIGH>; spi-max-frequency = <24000000>; - accel-pwr-mode = ; - accel-odr = ; + accel-pwr-mode = ; + accel-odr = ; accel-fs = ; - gyro-pwr-mode = ; - gyro-odr = ; + accel-aaf-bw = ; + gyro-pwr-mode = ; + gyro-odr = ; gyro-fs = ; + gyro-aaf-bw = ; }; spi_adc: adc@1 { compatible = "ti,ads7052"; diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 76a8cff9b96bb..f289b46550426 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -40,7 +40,7 @@ add_subdirectory_ifdef(CONFIG_HP206C hp206c) add_subdirectory_ifdef(CONFIG_HS300X hs300x) add_subdirectory_ifdef(CONFIG_ICM42605 tdk/icm42605) add_subdirectory_ifdef(CONFIG_ICM42670 tdk/icm42670) -add_subdirectory_ifdef(CONFIG_ICM42688 tdk/icm42688) +add_subdirectory_ifdef(CONFIG_ICM4268X tdk/icm4268x) add_subdirectory_ifdef(CONFIG_ICP10125 tdk/icp10125) add_subdirectory_ifdef(CONFIG_IST8310 ist8310) add_subdirectory_ifdef(CONFIG_ISL29035 isl29035) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index d347443ad4628..a2e896de5d0e5 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -124,7 +124,7 @@ source "drivers/sensor/hp206c/Kconfig" source "drivers/sensor/hs300x/Kconfig" source "drivers/sensor/tdk/icm42605/Kconfig" source "drivers/sensor/tdk/icm42670/Kconfig" -source "drivers/sensor/tdk/icm42688/Kconfig" +source "drivers/sensor/tdk/icm4268x/Kconfig" source "drivers/sensor/tdk/icp10125/Kconfig" source "drivers/sensor/isl29035/Kconfig" source "drivers/sensor/ist8310/Kconfig" diff --git a/drivers/sensor/tdk/icm42688/CMakeLists.txt b/drivers/sensor/tdk/icm42688/CMakeLists.txt deleted file mode 100644 index fbc63b6a4b229..0000000000000 --- a/drivers/sensor/tdk/icm42688/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() - -zephyr_library_sources( - icm42688.c - icm42688_common.c - icm42688_spi.c -) - -zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm42688_rtio.c) -zephyr_library_sources_ifdef(CONFIG_ICM42688_DECODER icm42688_decoder.c) -zephyr_library_sources_ifdef(CONFIG_ICM42688_STREAM icm42688_rtio_stream.c) -zephyr_library_sources_ifdef(CONFIG_ICM42688_TRIGGER icm42688_trigger.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_ICM42688 icm42688_emul.c) -zephyr_include_directories_ifdef(CONFIG_EMUL_ICM42688 .) diff --git a/drivers/sensor/tdk/icm42688/Kconfig b/drivers/sensor/tdk/icm42688/Kconfig deleted file mode 100644 index 413b199c1eabc..0000000000000 --- a/drivers/sensor/tdk/icm42688/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -# ICM42688-P Six-Axis Motion Tracking device configuration options -# -# Copyright (c) 2022 Intel Corporation -# Copyright (c) 2024 Croxel Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -menuconfig ICM42688 - bool "ICM42688 Six-Axis Motion Tracking Device" - default y - depends on DT_HAS_INVENSENSE_ICM42688_ENABLED - select SPI - select RTIO_WORKQ if SENSOR_ASYNC_API - help - Enable driver for ICM42688 SPI-based six-axis motion tracking device. - -if ICM42688 - -config EMUL_ICM42688 - bool "Emulator for the ICM42688" - default y - depends on EMUL - help - Enable the hardware emulator for the ICM42688. Doing so allows exercising - sensor APIs for this IMU in native_sim and qemu. - -config ICM42688_DECODER - bool "ICM42688 decoder logic" - default y - select SENSOR_ASYNC_API - help - Compile the ICM42688 decoder API which allows decoding raw data returned - from the sensor. - -choice - prompt "Trigger mode" - default ICM42688_TRIGGER_NONE if ICM42688_STREAM - default ICM42688_TRIGGER_GLOBAL_THREAD - help - Specify the type of triggering to be used by the driver - -config ICM42688_TRIGGER_NONE - bool "No trigger" - -config ICM42688_TRIGGER_GLOBAL_THREAD - bool "Use global thread" - select ICM42688_TRIGGER - -config ICM42688_TRIGGER_OWN_THREAD - bool "Use own thread" - select ICM42688_TRIGGER - -endchoice - -config ICM42688_STREAM - bool "Use hardware FIFO to stream data" - select ICM42688_TRIGGER - default y - depends on SPI_RTIO - depends on SENSOR_ASYNC_API - help - Use this config option to enable streaming sensor data via RTIO subsystem. - -config ICM42688_TRIGGER - bool - -config ICM42688_THREAD_PRIORITY - int "Own thread priority" - depends on ICM42688_TRIGGER_OWN_THREAD - default 10 - help - The priority of the thread used for handling interrupts. - -config ICM42688_THREAD_STACK_SIZE - int "Own thread stack size" - depends on ICM42688_TRIGGER_OWN_THREAD - default 1024 - help - The thread stack size. - -endif # ICM42688 diff --git a/drivers/sensor/tdk/icm42688/icm42688.c b/drivers/sensor/tdk/icm42688/icm42688.c deleted file mode 100644 index febb4612efaf8..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2022 Esco Medical ApS - * Copyright (c) 2020 TDK Invensense - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT invensense_icm42688 - -#include -#include -#include - -#include "icm42688.h" -#include "icm42688_decoder.h" -#include "icm42688_reg.h" -#include "icm42688_rtio.h" -#include "icm42688_spi.h" -#include "icm42688_trigger.h" - -#include -LOG_MODULE_REGISTER(ICM42688, CONFIG_SENSOR_LOG_LEVEL); - -static void icm42688_convert_accel(struct sensor_value *val, int16_t raw_val, - struct icm42688_cfg *cfg) -{ - icm42688_accel_ms(cfg, (int32_t)raw_val, &val->val1, &val->val2); -} - -static void icm42688_convert_gyro(struct sensor_value *val, int16_t raw_val, - struct icm42688_cfg *cfg) -{ - icm42688_gyro_rads(cfg, (int32_t)raw_val, &val->val1, &val->val2); -} - -static inline void icm42688_convert_temp(struct sensor_value *val, int16_t raw_val) -{ - icm42688_temp_c((int32_t)raw_val, &val->val1, &val->val2); -} - -int icm42688_channel_parse_readings(enum sensor_channel chan, int16_t readings[7], - struct icm42688_cfg *cfg, struct sensor_value *val) -{ - switch (chan) { - case SENSOR_CHAN_ACCEL_XYZ: - icm42688_convert_accel(&val[0], readings[1], cfg); - icm42688_convert_accel(&val[1], readings[2], cfg); - icm42688_convert_accel(&val[2], readings[3], cfg); - break; - case SENSOR_CHAN_ACCEL_X: - icm42688_convert_accel(val, readings[1], cfg); - break; - case SENSOR_CHAN_ACCEL_Y: - icm42688_convert_accel(val, readings[2], cfg); - break; - case SENSOR_CHAN_ACCEL_Z: - icm42688_convert_accel(val, readings[3], cfg); - break; - case SENSOR_CHAN_GYRO_XYZ: - icm42688_convert_gyro(&val[0], readings[4], cfg); - icm42688_convert_gyro(&val[1], readings[5], cfg); - icm42688_convert_gyro(&val[2], readings[6], cfg); - break; - case SENSOR_CHAN_GYRO_X: - icm42688_convert_gyro(val, readings[4], cfg); - break; - case SENSOR_CHAN_GYRO_Y: - icm42688_convert_gyro(val, readings[5], cfg); - break; - case SENSOR_CHAN_GYRO_Z: - icm42688_convert_gyro(val, readings[6], cfg); - break; - case SENSOR_CHAN_DIE_TEMP: - icm42688_convert_temp(val, readings[0]); - break; - default: - return -ENOTSUP; - } - - return 0; -} - -static int icm42688_channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) -{ - struct icm42688_dev_data *data = dev->data; - - return icm42688_channel_parse_readings(chan, data->readings, &data->cfg, val); -} - -static int icm42688_sample_fetch(const struct device *dev, enum sensor_channel chan) -{ - uint8_t status; - struct icm42688_dev_data *data = dev->data; - const struct icm42688_dev_cfg *cfg = dev->config; - - int res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); - - if (res) { - return res; - } - - if (!FIELD_GET(BIT_INT_STATUS_DATA_RDY, status)) { - return -EBUSY; - } - - uint8_t readings[14]; - - res = icm42688_read_all(dev, readings); - - if (res) { - return res; - } - - for (int i = 0; i < 7; i++) { - data->readings[i] = sys_le16_to_cpu((readings[i * 2] << 8) | readings[i * 2 + 1]); - } - - return 0; -} - -static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, const struct sensor_value *val) -{ - const struct icm42688_dev_data *data = dev->data; - struct icm42688_cfg new_config = data->cfg; - int res = 0; - - __ASSERT_NO_MSG(val != NULL); - - switch (chan) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - new_config.accel_odr = icm42688_accel_hz_to_reg(val->val1); - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - new_config.accel_fs = icm42688_accel_fs_to_reg(sensor_ms2_to_g(val)); - } else { - LOG_ERR("Unsupported attribute"); - res = -ENOTSUP; - } - break; - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - new_config.gyro_odr = icm42688_gyro_odr_to_reg(val->val1); - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - new_config.gyro_fs = icm42688_gyro_fs_to_reg(sensor_rad_to_degrees(val)); - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - case SENSOR_CHAN_ALL: - if (attr == SENSOR_ATTR_BATCH_DURATION) { - if (val->val1 < 0) { - return -EINVAL; - } - new_config.batch_ticks = val->val1; - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - default: - LOG_ERR("Unsupported channel"); - res = -EINVAL; - break; - } - - if (res) { - return res; - } - return icm42688_safely_configure(dev, &new_config); -} - -static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, struct sensor_value *val) -{ - const struct icm42688_dev_data *data = dev->data; - const struct icm42688_cfg *cfg = &data->cfg; - int res = 0; - - __ASSERT_NO_MSG(val != NULL); - - switch (chan) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - icm42688_accel_reg_to_hz(cfg->accel_odr, val); - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - icm42688_accel_reg_to_fs(cfg->accel_fs, val); - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - icm42688_gyro_reg_to_odr(cfg->gyro_odr, val); - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - icm42688_gyro_reg_to_fs(cfg->gyro_fs, val); - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - case SENSOR_CHAN_ALL: - if (attr == SENSOR_ATTR_BATCH_DURATION) { - val->val1 = cfg->batch_ticks; - val->val2 = 0; - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - default: - LOG_ERR("Unsupported channel"); - res = -EINVAL; - break; - } - - return res; -} - -static const struct sensor_driver_api icm42688_driver_api = { - .sample_fetch = icm42688_sample_fetch, - .channel_get = icm42688_channel_get, - .attr_set = icm42688_attr_set, - .attr_get = icm42688_attr_get, -#ifdef CONFIG_ICM42688_TRIGGER - .trigger_set = icm42688_trigger_set, -#endif - .get_decoder = icm42688_get_decoder, -#ifdef CONFIG_SENSOR_ASYNC_API - .submit = icm42688_submit, -#endif -}; - -int icm42688_init(const struct device *dev) -{ - struct icm42688_dev_data *data = dev->data; - const struct icm42688_dev_cfg *cfg = dev->config; - int res; - - if (!spi_is_ready_dt(&cfg->spi)) { - LOG_ERR("SPI bus is not ready"); - return -ENODEV; - } - - if (icm42688_reset(dev)) { - LOG_ERR("could not initialize sensor"); - return -EIO; - } - -#ifdef CONFIG_ICM42688_TRIGGER - res = icm42688_trigger_init(dev); - if (res != 0) { - LOG_ERR("Failed to initialize triggers"); - return res; - } -#endif - - res = icm42688_configure(dev, &data->cfg); - if (res != 0) { - LOG_ERR("Failed to configure"); - return res; - } - - return 0; -} - -#ifndef CONFIG_ICM42688_TRIGGER -void icm42688_lock(const struct device *dev) -{ - ARG_UNUSED(dev); -} -void icm42688_unlock(const struct device *dev) -{ - ARG_UNUSED(dev); -} -#endif - -/* device defaults to spi mode 0/3 support */ -#define ICM42688_SPI_CFG \ - SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB - -#define ICM42688_RTIO_DEFINE(inst) \ - SPI_DT_IODEV_DEFINE(icm42688_spi_iodev_##inst, DT_DRV_INST(inst), ICM42688_SPI_CFG, 0U); \ - RTIO_DEFINE(icm42688_rtio_##inst, 8, 4); - -#define ICM42688_DT_CONFIG_INIT(inst) \ - { \ - .accel_pwr_mode = DT_INST_PROP(inst, accel_pwr_mode), \ - .accel_fs = DT_INST_PROP(inst, accel_fs), \ - .accel_odr = DT_INST_PROP(inst, accel_odr), \ - .gyro_pwr_mode = DT_INST_PROP(inst, gyro_pwr_mode), \ - .gyro_fs = DT_INST_PROP(inst, gyro_fs), \ - .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ - .temp_dis = false, \ - .fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM), \ - .batch_ticks = 0, \ - .fifo_hires = false, \ - .interrupt1_drdy = false, \ - .interrupt1_fifo_ths = false, \ - .interrupt1_fifo_full = false \ - } - -#define ICM42688_DEFINE_DATA(inst) \ - IF_ENABLED(CONFIG_ICM42688_STREAM, (ICM42688_RTIO_DEFINE(inst))); \ - static struct icm42688_dev_data icm42688_driver_##inst = { \ - .cfg = ICM42688_DT_CONFIG_INIT(inst), \ - IF_ENABLED(CONFIG_ICM42688_STREAM, (.r = &icm42688_rtio_##inst, \ - .spi_iodev = &icm42688_spi_iodev_##inst,)) \ - }; - -#define ICM42688_INIT(inst) \ - ICM42688_DEFINE_DATA(inst); \ - \ - static const struct icm42688_dev_cfg icm42688_cfg_##inst = { \ - .spi = SPI_DT_SPEC_INST_GET(inst, ICM42688_SPI_CFG, 0U), \ - .gpio_int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ - }; \ - \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, icm42688_init, NULL, &icm42688_driver_##inst, \ - &icm42688_cfg_##inst, POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, &icm42688_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(ICM42688_INIT) diff --git a/drivers/sensor/tdk/icm42688/icm42688.h b/drivers/sensor/tdk/icm42688/icm42688.h deleted file mode 100644 index 5ca61a82cfae8..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688.h +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_H_ - -#include -#include -#include -#include -#include -#include - -static inline uint8_t icm42688_accel_fs_to_reg(uint8_t g) -{ - if (g >= 16) { - return ICM42688_DT_ACCEL_FS_16; - } else if (g >= 8) { - return ICM42688_DT_ACCEL_FS_8; - } else if (g >= 4) { - return ICM42688_DT_ACCEL_FS_4; - } else { - return ICM42688_DT_ACCEL_FS_2; - } -} - -static inline void icm42688_accel_reg_to_fs(uint8_t fs, struct sensor_value *out) -{ - switch (fs) { - case ICM42688_DT_ACCEL_FS_16: - sensor_g_to_ms2(16, out); - return; - case ICM42688_DT_ACCEL_FS_8: - sensor_g_to_ms2(8, out); - return; - case ICM42688_DT_ACCEL_FS_4: - sensor_g_to_ms2(4, out); - return; - case ICM42688_DT_ACCEL_FS_2: - sensor_g_to_ms2(2, out); - return; - } -} - -static inline uint8_t icm42688_gyro_fs_to_reg(uint16_t dps) -{ - if (dps >= 2000) { - return ICM42688_DT_GYRO_FS_2000; - } else if (dps >= 1000) { - return ICM42688_DT_GYRO_FS_1000; - } else if (dps >= 500) { - return ICM42688_DT_GYRO_FS_500; - } else if (dps >= 250) { - return ICM42688_DT_GYRO_FS_250; - } else if (dps >= 125) { - return ICM42688_DT_GYRO_FS_125; - } else if (dps >= 62) { - return ICM42688_DT_GYRO_FS_62_5; - } else if (dps >= 31) { - return ICM42688_DT_GYRO_FS_31_25; - } else { - return ICM42688_DT_GYRO_FS_15_625; - } -} - -static inline void icm42688_gyro_reg_to_fs(uint8_t fs, struct sensor_value *out) -{ - switch (fs) { - case ICM42688_DT_GYRO_FS_2000: - sensor_degrees_to_rad(2000, out); - return; - case ICM42688_DT_GYRO_FS_1000: - sensor_degrees_to_rad(1000, out); - return; - case ICM42688_DT_GYRO_FS_500: - sensor_degrees_to_rad(500, out); - return; - case ICM42688_DT_GYRO_FS_250: - sensor_degrees_to_rad(250, out); - return; - case ICM42688_DT_GYRO_FS_125: - sensor_degrees_to_rad(125, out); - return; - case ICM42688_DT_GYRO_FS_62_5: - sensor_10udegrees_to_rad(6250000, out); - return; - case ICM42688_DT_GYRO_FS_31_25: - sensor_10udegrees_to_rad(3125000, out); - return; - case ICM42688_DT_GYRO_FS_15_625: - sensor_10udegrees_to_rad(1562500, out); - return; - } -} - -static inline uint8_t icm42688_accel_hz_to_reg(uint16_t hz) -{ - if (hz >= 32000) { - return ICM42688_DT_ACCEL_ODR_32000; - } else if (hz >= 16000) { - return ICM42688_DT_ACCEL_ODR_16000; - } else if (hz >= 8000) { - return ICM42688_DT_ACCEL_ODR_8000; - } else if (hz >= 4000) { - return ICM42688_DT_ACCEL_ODR_4000; - } else if (hz >= 2000) { - return ICM42688_DT_ACCEL_ODR_2000; - } else if (hz >= 1000) { - return ICM42688_DT_ACCEL_ODR_1000; - } else if (hz >= 500) { - return ICM42688_DT_ACCEL_ODR_500; - } else if (hz >= 200) { - return ICM42688_DT_ACCEL_ODR_200; - } else if (hz >= 100) { - return ICM42688_DT_ACCEL_ODR_100; - } else if (hz >= 50) { - return ICM42688_DT_ACCEL_ODR_50; - } else if (hz >= 25) { - return ICM42688_DT_ACCEL_ODR_25; - } else if (hz >= 12) { - return ICM42688_DT_ACCEL_ODR_12_5; - } else if (hz >= 6) { - return ICM42688_DT_ACCEL_ODR_6_25; - } else if (hz >= 3) { - return ICM42688_DT_ACCEL_ODR_3_125; - } else { - return ICM42688_DT_ACCEL_ODR_1_5625; - } -} - -static inline void icm42688_accel_reg_to_hz(uint8_t odr, struct sensor_value *out) -{ - switch (odr) { - case ICM42688_DT_ACCEL_ODR_32000: - out->val1 = 32000; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_16000: - out->val1 = 1600; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_8000: - out->val1 = 8000; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_4000: - out->val1 = 4000; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_2000: - out->val1 = 2000; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_1000: - out->val1 = 1000; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_500: - out->val1 = 500; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_200: - out->val1 = 200; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_100: - out->val1 = 100; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_50: - out->val1 = 50; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_25: - out->val1 = 25; - out->val2 = 0; - return; - case ICM42688_DT_ACCEL_ODR_12_5: - out->val1 = 12; - out->val2 = 500000; - return; - case ICM42688_DT_ACCEL_ODR_6_25: - out->val1 = 6; - out->val2 = 250000; - return; - case ICM42688_DT_ACCEL_ODR_3_125: - out->val1 = 3; - out->val2 = 125000; - return; - case ICM42688_DT_ACCEL_ODR_1_5625: - out->val1 = 1; - out->val2 = 562500; - return; - } -} - -static inline uint8_t icm42688_gyro_odr_to_reg(uint16_t hz) -{ - if (hz >= 32000) { - return ICM42688_DT_GYRO_ODR_32000; - } else if (hz >= 16000) { - return ICM42688_DT_GYRO_ODR_16000; - } else if (hz >= 8000) { - return ICM42688_DT_GYRO_ODR_8000; - } else if (hz >= 4000) { - return ICM42688_DT_GYRO_ODR_4000; - } else if (hz >= 2000) { - return ICM42688_DT_GYRO_ODR_2000; - } else if (hz >= 1000) { - return ICM42688_DT_GYRO_ODR_1000; - } else if (hz >= 500) { - return ICM42688_DT_GYRO_ODR_500; - } else if (hz >= 200) { - return ICM42688_DT_GYRO_ODR_200; - } else if (hz >= 100) { - return ICM42688_DT_GYRO_ODR_100; - } else if (hz >= 50) { - return ICM42688_DT_GYRO_ODR_50; - } else if (hz >= 25) { - return ICM42688_DT_GYRO_ODR_25; - } else { - return ICM42688_DT_GYRO_ODR_12_5; - } -} - -static inline void icm42688_gyro_reg_to_odr(uint8_t odr, struct sensor_value *out) -{ - switch (odr) { - case ICM42688_DT_GYRO_ODR_32000: - out->val1 = 32000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_16000: - out->val1 = 16000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_8000: - out->val1 = 8000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_4000: - out->val1 = 4000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_2000: - out->val1 = 2000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_1000: - out->val1 = 1000; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_500: - out->val1 = 500; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_200: - out->val1 = 200; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_100: - out->val1 = 100; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_50: - out->val1 = 50; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_25: - out->val1 = 25; - out->val2 = 0; - return; - case ICM42688_DT_GYRO_ODR_12_5: - out->val1 = 12; - out->val2 = 500000; - return; - } -} - -/** - * @brief All sensor configuration options - */ -struct icm42688_cfg { - uint8_t accel_pwr_mode; - uint8_t accel_fs; - uint8_t accel_odr; - /* TODO accel signal processing options */ - - uint8_t gyro_pwr_mode; - uint8_t gyro_fs; - uint8_t gyro_odr; - /* TODO gyro signal processing options */ - - bool temp_dis; - /* TODO temp signal processing options */ - - /* TODO timestamp options */ - - bool fifo_en; - int32_t batch_ticks; - bool fifo_hires; - /* TODO additional FIFO options */ - - /* TODO interrupt options */ - bool interrupt1_drdy; - bool interrupt1_fifo_ths; - bool interrupt1_fifo_full; -}; - -struct icm42688_trigger_entry { - struct sensor_trigger trigger; - sensor_trigger_handler_t handler; -}; - -/** - * @brief Device data (struct device) - */ -struct icm42688_dev_data { - struct icm42688_cfg cfg; -#ifdef CONFIG_ICM42688_TRIGGER -#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) - K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ICM42688_THREAD_STACK_SIZE); - struct k_thread thread; - struct k_sem gpio_sem; -#elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) - struct k_work work; -#endif -#ifdef CONFIG_ICM42688_STREAM - struct rtio_iodev_sqe *streaming_sqe; - struct rtio *r; - struct rtio_iodev *spi_iodev; - uint8_t int_status; - uint16_t fifo_count; - uint64_t timestamp; - atomic_t reading_fifo; -#endif /* CONFIG_ICM42688_STREAM */ - const struct device *dev; - struct gpio_callback gpio_cb; - sensor_trigger_handler_t data_ready_handler; - const struct sensor_trigger *data_ready_trigger; - struct k_mutex mutex; -#endif /* CONFIG_ICM42688_TRIGGER */ - - int16_t readings[7]; -}; - -/** - * @brief Device config (struct device) - */ -struct icm42688_dev_cfg { - struct spi_dt_spec spi; - struct gpio_dt_spec gpio_int1; - struct gpio_dt_spec gpio_int2; -}; - -/** - * @brief Reset the sensor - * - * @param dev icm42688 device pointer - * - * @retval 0 success - * @retval -EINVAL Reset status or whoami register returned unexpected value. - */ -int icm42688_reset(const struct device *dev); - -/** - * @brief (Re)Configure the sensor with the given configuration - * - * @param dev icm42688 device pointer - * @param cfg icm42688_cfg pointer - * - * @retval 0 success - * @retval -errno Error - */ -int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg); - - -/** - * @brief Safely (re)Configure the sensor with the given configuration - * - * Will rollback to prior configuration if new configuration is invalid - * - * @param dev icm42688 device pointer - * @param cfg icm42688_cfg pointer - * - * @retval 0 success - * @retval -errno Error - */ -int icm42688_safely_configure(const struct device *dev, struct icm42688_cfg *cfg); - -/** - * @brief Reads all channels - * - * Regardless of what is enabled/disabled this reads all data registers - * as the time to read the 14 bytes at 1MHz is going to be 112 us which - * is less time than a SPI transaction takes to setup typically. - * - * @param dev icm42688 device pointer - * @param buf 14 byte buffer to store data values (7 channels, 2 bytes each) - * - * @retval 0 success - * @retval -errno Error - */ -int icm42688_read_all(const struct device *dev, uint8_t data[14]); - -/** - * @brief Convert icm42688 accelerometer value to useful g values - * - * @param cfg icm42688_cfg current device configuration - * @param in raw data value in int32_t format - * @param out_g whole G's output in int32_t - * @param out_ug micro (1/1000000) of a G output as uint32_t - */ -static inline void icm42688_accel_g(struct icm42688_cfg *cfg, int32_t in, int32_t *out_g, - uint32_t *out_ug) -{ - int32_t sensitivity; - - switch (cfg->accel_fs) { - case ICM42688_DT_ACCEL_FS_2: - sensitivity = 16384; - break; - case ICM42688_DT_ACCEL_FS_4: - sensitivity = 8192; - break; - case ICM42688_DT_ACCEL_FS_8: - sensitivity = 4096; - break; - case ICM42688_DT_ACCEL_FS_16: - sensitivity = 2048; - break; - default: - CODE_UNREACHABLE; - } - - /* Whole g's */ - *out_g = in / sensitivity; - - /* Micro g's */ - *out_ug = ((abs(in) - (abs((*out_g)) * sensitivity)) * 1000000) / sensitivity; -} - -/** - * @brief Convert icm42688 gyroscope value to useful deg/s values - * - * @param cfg icm42688_cfg current device configuration - * @param in raw data value in int32_t format - * @param out_dps whole deg/s output in int32_t - * @param out_udps micro (1/1000000) deg/s as uint32_t - */ -static inline void icm42688_gyro_dps(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_dps, - uint32_t *out_udps) -{ - int64_t sensitivity; - - switch (cfg->gyro_fs) { - case ICM42688_DT_GYRO_FS_2000: - sensitivity = 164; - break; - case ICM42688_DT_GYRO_FS_1000: - sensitivity = 328; - break; - case ICM42688_DT_GYRO_FS_500: - sensitivity = 655; - break; - case ICM42688_DT_GYRO_FS_250: - sensitivity = 1310; - break; - case ICM42688_DT_GYRO_FS_125: - sensitivity = 2620; - break; - case ICM42688_DT_GYRO_FS_62_5: - sensitivity = 5243; - break; - case ICM42688_DT_GYRO_FS_31_25: - sensitivity = 10486; - break; - case ICM42688_DT_GYRO_FS_15_625: - sensitivity = 20972; - break; - default: - CODE_UNREACHABLE; - } - - int32_t in10 = in * 10; - - /* Whole deg/s */ - *out_dps = in10 / sensitivity; - - /* Micro deg/s */ - *out_udps = ((int64_t)(llabs(in10) - (llabs((*out_dps)) * sensitivity)) * 1000000LL) / - sensitivity; -} - -/** - * @brief Convert icm42688 accelerometer value to useful m/s^2 values - * - * @param cfg icm42688_cfg current device configuration - * @param in raw data value in int32_t format - * @param out_ms meters/s^2 (whole) output in int32_t - * @param out_ums micrometers/s^2 output as uint32_t - */ -static inline void icm42688_accel_ms(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_ms, - int32_t *out_ums) -{ - int64_t sensitivity = 0; /* value equivalent for 1g */ - - switch (cfg->accel_fs) { - case ICM42688_DT_ACCEL_FS_2: - sensitivity = 16384; - break; - case ICM42688_DT_ACCEL_FS_4: - sensitivity = 8192; - break; - case ICM42688_DT_ACCEL_FS_8: - sensitivity = 4096; - break; - case ICM42688_DT_ACCEL_FS_16: - sensitivity = 2048; - break; - } - - /* Convert to micrometers/s^2 */ - int64_t in_ms = in * SENSOR_G; - - /* meters/s^2 whole values */ - *out_ms = in_ms / (sensitivity * 1000000LL); - - /* micrometers/s^2 */ - *out_ums = (in_ms - (*out_ms * sensitivity * 1000000LL)) / sensitivity; -} - -/** - * @brief Convert icm42688 gyroscope value to useful rad/s values - * - * @param cfg icm42688_cfg current device configuration - * @param in raw data value in int32_t format - * @param out_rads whole rad/s output in int32_t - * @param out_urads microrad/s as uint32_t - */ -static inline void icm42688_gyro_rads(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_rads, - int32_t *out_urads) -{ - int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */ - - switch (cfg->gyro_fs) { - case ICM42688_DT_GYRO_FS_2000: - sensitivity = 164; - break; - case ICM42688_DT_GYRO_FS_1000: - sensitivity = 328; - break; - case ICM42688_DT_GYRO_FS_500: - sensitivity = 655; - break; - case ICM42688_DT_GYRO_FS_250: - sensitivity = 1310; - break; - case ICM42688_DT_GYRO_FS_125: - sensitivity = 2620; - break; - case ICM42688_DT_GYRO_FS_62_5: - sensitivity = 5243; - break; - case ICM42688_DT_GYRO_FS_31_25: - sensitivity = 10486; - break; - case ICM42688_DT_GYRO_FS_15_625: - sensitivity = 20972; - break; - } - - int64_t in10_rads = (int64_t)in * SENSOR_PI * 10LL; - - /* Whole rad/s */ - *out_rads = in10_rads / (sensitivity * 180LL * 1000000LL); - - /* microrad/s */ - *out_urads = - (in10_rads - (*out_rads * sensitivity * 180LL * 1000000LL)) / (sensitivity * 180LL); -} - -/** - * @brief Convert icm42688 temp value to useful celsius values - * - * @param cfg icm42688_cfg current device configuration - * @param in raw data value in int32_t format - * @param out_c whole celsius output in int32_t - * @param out_uc micro (1/1000000) celsius as uint32_t - */ -static inline void icm42688_temp_c(int32_t in, int32_t *out_c, uint32_t *out_uc) -{ - int64_t sensitivity = 13248; /* value equivalent for x100 1c */ - - /* Offset by 25 degrees Celsius */ - int64_t in100 = (in * 100) + (25 * sensitivity); - - /* Whole celsius */ - *out_c = in100 / sensitivity; - - /* Micro celsius */ - *out_uc = ((in100 - (*out_c) * sensitivity) * INT64_C(1000000)) / sensitivity; -} - -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_H_ */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_common.c b/drivers/sensor/tdk/icm42688/icm42688_common.c deleted file mode 100644 index 3a0c79869be9c..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_common.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2022 Esco Medical ApS - * Copyright (c) 2020 TDK Invensense - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "icm42688.h" -#include "icm42688_reg.h" -#include "icm42688_spi.h" -#include "icm42688_trigger.h" - -#include -LOG_MODULE_REGISTER(ICM42688_LL, CONFIG_SENSOR_LOG_LEVEL); - -int icm42688_reset(const struct device *dev) -{ - int res; - uint8_t value; - const struct icm42688_dev_cfg *dev_cfg = dev->config; - - /* start up time for register read/write after POR is 1ms and supply ramp time is 3ms */ - k_msleep(3); - - /* perform a soft reset to ensure a clean slate, reset bit will auto-clear */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_DEVICE_CONFIG, BIT_SOFT_RESET); - - if (res) { - LOG_ERR("write REG_SIGNAL_PATH_RESET failed"); - return res; - } - - /* wait for soft reset to take effect */ - k_msleep(SOFT_RESET_TIME_MS); - - /* clear reset done int flag */ - res = icm42688_spi_read(&dev_cfg->spi, REG_INT_STATUS, &value, 1); - - if (res) { - return res; - } - - if (FIELD_GET(BIT_INT_STATUS_RESET_DONE, value) != 1) { - LOG_ERR("unexpected RESET_DONE value, %i", value); - return -EINVAL; - } - - res = icm42688_spi_read(&dev_cfg->spi, REG_WHO_AM_I, &value, 1); - if (res) { - return res; - } - - if (value != WHO_AM_I_ICM42688) { - LOG_ERR("invalid WHO_AM_I value, was %i but expected %i", value, WHO_AM_I_ICM42688); - return -EINVAL; - } - - return 0; -} - -static uint16_t icm42688_compute_fifo_wm(const struct icm42688_cfg *cfg) -{ - const bool accel_enabled = cfg->accel_pwr_mode != ICM42688_DT_ACCEL_OFF; - const bool gyro_enabled = cfg->gyro_pwr_mode != ICM42688_DT_GYRO_OFF; - const int pkt_size = cfg->fifo_hires ? 20 : (accel_enabled && gyro_enabled ? 16 : 8); - int accel_modr = 0; - int gyro_modr = 0; - int64_t modr; - - if (cfg->batch_ticks == 0 || (!accel_enabled && !gyro_enabled)) { - return 0; - } - - if (accel_enabled) { - struct sensor_value val = {0}; - - icm42688_accel_reg_to_hz(cfg->accel_odr, &val); - accel_modr = sensor_value_to_micro(&val) / 1000; - } - if (gyro_enabled) { - struct sensor_value val = {0}; - - icm42688_gyro_reg_to_odr(cfg->gyro_odr, &val); - gyro_modr = sensor_value_to_micro(&val) / 1000; - } - - if (accel_modr == 0) { - modr = gyro_modr; - } else if (gyro_modr == 0) { - modr = accel_modr; - } else { - /* Need to find the least common multiplier (LCM) */ - int n1 = accel_modr; - int n2 = gyro_modr; - - while (n1 != n2) { - if (n1 > n2) { - n1 -= n2; - } else { - n2 -= n1; - } - } - LOG_DBG("GCD=%d", n1); - modr = ((int64_t)accel_modr * (int64_t)gyro_modr) / n1; - } - /* At this point we have 'modr' as mHz which is 1 / msec. */ - - /* Convert 'modr' to bytes * batch_ticks / msec */ - modr *= (int64_t)cfg->batch_ticks * pkt_size; - - /* 'modr' = byte_ticks_per_msec / kticks_per_sec */ - modr = DIV_ROUND_UP(modr, CONFIG_SYS_CLOCK_TICKS_PER_SEC * INT64_C(1000)); - - return (uint16_t)MIN(modr, 0x7ff); -} - -int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) -{ - struct icm42688_dev_data *dev_data = dev->data; - const struct icm42688_dev_cfg *dev_cfg = dev->config; - int res; - - /* Disable interrupts, reconfigured at end */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, 0); - - /* if fifo is enabled right now, disable and flush */ - if (dev_data->cfg.fifo_en) { - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, - FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_BYPASS)); - - if (res != 0) { - LOG_ERR("Error writing FIFO_CONFIG"); - return -EINVAL; - } - - res = icm42688_spi_single_write(&dev_cfg->spi, REG_SIGNAL_PATH_RESET, - FIELD_PREP(BIT_FIFO_FLUSH, 1)); - - if (res != 0) { - LOG_ERR("Error flushing fifo"); - return -EINVAL; - } - } - - /* TODO maybe do the next few steps intelligently by checking current config */ - - /* Power management to set gyro/accel modes */ - uint8_t pwr_mgmt0 = FIELD_PREP(MASK_GYRO_MODE, cfg->gyro_pwr_mode) | - FIELD_PREP(MASK_ACCEL_MODE, cfg->accel_pwr_mode) | - FIELD_PREP(BIT_TEMP_DIS, cfg->temp_dis); - - LOG_DBG("PWR_MGMT0 (0x%x) 0x%x", REG_PWR_MGMT0, pwr_mgmt0); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_PWR_MGMT0, pwr_mgmt0); - - if (res != 0) { - LOG_ERR("Error writing PWR_MGMT0"); - return -EINVAL; - } - - /* Need to wait at least 200us before updating more registers - * see datasheet 14.36 - */ - k_busy_wait(250); - - uint8_t accel_config0 = FIELD_PREP(MASK_ACCEL_ODR, cfg->accel_odr) | - FIELD_PREP(MASK_ACCEL_UI_FS_SEL, cfg->accel_fs); - - LOG_DBG("ACCEL_CONFIG0 (0x%x) 0x%x", REG_ACCEL_CONFIG0, accel_config0); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_ACCEL_CONFIG0, accel_config0); - if (res != 0) { - LOG_ERR("Error writing ACCEL_CONFIG0"); - return -EINVAL; - } - - uint8_t gyro_config0 = FIELD_PREP(MASK_GYRO_ODR, cfg->gyro_odr) | - FIELD_PREP(MASK_GYRO_UI_FS_SEL, cfg->gyro_fs); - - LOG_DBG("GYRO_CONFIG0 (0x%x) 0x%x", REG_GYRO_CONFIG0, gyro_config0); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_GYRO_CONFIG0, gyro_config0); - if (res != 0) { - LOG_ERR("Error writing GYRO_CONFIG0"); - return -EINVAL; - } - - /* - * Accelerometer sensor need at least 10ms startup time - * Gyroscope sensor need at least 30ms startup time - */ - k_msleep(50); - - /* Ensure FIFO is in bypass mode */ - uint8_t fifo_config_bypass = FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_BYPASS); - - LOG_DBG("FIFO_CONFIG (0x%x) 0x%x", REG_FIFO_CONFIG, fifo_config_bypass); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, fifo_config_bypass); - if (res != 0) { - LOG_ERR("Error writing FIFO_CONFIG"); - return -EINVAL; - } - - /* Disable FSYNC */ - uint8_t tmst_config; - - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FSYNC_CONFIG, 0); - if (res != 0) { - LOG_ERR("Error writing FSYNC_CONFIG"); - return -EINVAL; - } - res = icm42688_spi_read(&dev_cfg->spi, REG_TMST_CONFIG, &tmst_config, 1); - if (res != 0) { - LOG_ERR("Error reading TMST_CONFIG"); - return -EINVAL; - } - res = icm42688_spi_single_write(&dev_cfg->spi, REG_TMST_CONFIG, tmst_config & ~BIT(1)); - if (res != 0) { - LOG_ERR("Error writing TMST_CONFIG"); - return -EINVAL; - } - - /* Pulse mode with async reset (resets interrupt line on int status read) */ - if (IS_ENABLED(CONFIG_ICM42688_TRIGGER)) { - res = icm42688_trigger_enable_interrupt(dev, cfg); - } else { - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); - } - if (res) { - LOG_ERR("Error writing to INT_CONFIG"); - return res; - } - - uint8_t int_config1 = 0; - - if ((cfg->accel_odr <= ICM42688_DT_ACCEL_ODR_4000 || - cfg->gyro_odr <= ICM42688_DT_GYRO_ODR_4000)) { - int_config1 = FIELD_PREP(BIT_INT_TPULSE_DURATION, 1) | - FIELD_PREP(BIT_INT_TDEASSERT_DISABLE, 1); - } - - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG1, int_config1); - if (res) { - LOG_ERR("Error writing to INT_CONFIG1"); - return res; - } - - /* fifo configuration steps if desired */ - if (cfg->fifo_en) { - LOG_INF("FIFO ENABLED"); - - /* Setup desired FIFO packet fields, maybe should base this on the other - * temp/accel/gyro en fields in cfg - */ - uint8_t fifo_cfg1 = - FIELD_PREP(BIT_FIFO_TEMP_EN, 1) | FIELD_PREP(BIT_FIFO_GYRO_EN, 1) | - FIELD_PREP(BIT_FIFO_ACCEL_EN, 1) | FIELD_PREP(BIT_FIFO_TMST_FSYNC_EN, 1); - - LOG_DBG("FIFO_CONFIG1 (0x%x) 0x%x", REG_FIFO_CONFIG1, fifo_cfg1); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG1, fifo_cfg1); - if (res != 0) { - LOG_ERR("Error writing FIFO_CONFIG1"); - return -EINVAL; - } - - /* Set watermark and interrupt handling first */ - uint16_t fifo_wm = icm42688_compute_fifo_wm(cfg); - uint8_t fifo_wml = fifo_wm & 0xFF; - - LOG_DBG("FIFO_CONFIG2( (0x%x)) (WM Low) 0x%x", REG_FIFO_CONFIG2, fifo_wml); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG2, fifo_wml); - if (res != 0) { - LOG_ERR("Error writing FIFO_CONFIG2"); - return -EINVAL; - } - - uint8_t fifo_wmh = (fifo_wm >> 8) & 0x0F; - - LOG_DBG("FIFO_CONFIG3 (0x%x) (WM High) 0x%x", REG_FIFO_CONFIG3, fifo_wmh); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG3, fifo_wmh); - if (res != 0) { - LOG_ERR("Error writing FIFO_CONFIG3"); - return -EINVAL; - } - - /* Begin streaming */ - uint8_t fifo_config = FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_STREAM); - - LOG_DBG("FIFO_CONFIG (0x%x) 0x%x", REG_FIFO_CONFIG, 1 << 6); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, fifo_config); - - /* Config interrupt source to only be fifo wm/full */ - uint8_t int_source0 = BIT_FIFO_FULL_INT1_EN | BIT_FIFO_THS_INT1_EN; - - LOG_DBG("INT_SOURCE0 (0x%x) 0x%x", REG_INT_SOURCE0, int_source0); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, int_source0); - if (res) { - return res; - } - } else { - LOG_INF("FIFO DISABLED"); - - /* No fifo mode so set data ready as interrupt source */ - uint8_t int_source0 = BIT_UI_DRDY_INT1_EN; - - LOG_DBG("INT_SOURCE0 (0x%x) 0x%x", REG_INT_SOURCE0, int_source0); - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, int_source0); - if (res) { - return res; - } - } - - return res; -} - -int icm42688_safely_configure(const struct device *dev, struct icm42688_cfg *cfg) -{ - struct icm42688_dev_data *drv_data = dev->data; - int ret = icm42688_configure(dev, cfg); - - if (ret == 0) { - drv_data->cfg = *cfg; - } else { - ret = icm42688_configure(dev, &drv_data->cfg); - } - - return ret; -} - -int icm42688_read_all(const struct device *dev, uint8_t data[14]) -{ - const struct icm42688_dev_cfg *dev_cfg = dev->config; - int res; - - res = icm42688_spi_read(&dev_cfg->spi, REG_TEMP_DATA1, data, 14); - - return res; -} diff --git a/drivers/sensor/tdk/icm42688/icm42688_decoder.c b/drivers/sensor/tdk/icm42688/icm42688_decoder.c deleted file mode 100644 index c01cc3f9c27e1..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_decoder.c +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Copyright (c) 2023 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "icm42688_decoder.h" -#include "icm42688_reg.h" -#include "icm42688.h" -#include - -#include -LOG_MODULE_REGISTER(ICM42688_DECODER, CONFIG_SENSOR_LOG_LEVEL); - -#define DT_DRV_COMPAT invensense_icm42688 - -static int icm42688_get_shift(enum sensor_channel channel, int accel_fs, int gyro_fs, int8_t *shift) -{ - switch (channel) { - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - switch (accel_fs) { - case ICM42688_DT_ACCEL_FS_2: - *shift = 5; - return 0; - case ICM42688_DT_ACCEL_FS_4: - *shift = 6; - return 0; - case ICM42688_DT_ACCEL_FS_8: - *shift = 7; - return 0; - case ICM42688_DT_ACCEL_FS_16: - *shift = 8; - return 0; - default: - return -EINVAL; - } - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - switch (gyro_fs) { - case ICM42688_DT_GYRO_FS_15_625: - *shift = -1; - return 0; - case ICM42688_DT_GYRO_FS_31_25: - *shift = 0; - return 0; - case ICM42688_DT_GYRO_FS_62_5: - *shift = 1; - return 0; - case ICM42688_DT_GYRO_FS_125: - *shift = 2; - return 0; - case ICM42688_DT_GYRO_FS_250: - *shift = 3; - return 0; - case ICM42688_DT_GYRO_FS_500: - *shift = 4; - return 0; - case ICM42688_DT_GYRO_FS_1000: - *shift = 5; - return 0; - case ICM42688_DT_GYRO_FS_2000: - *shift = 6; - return 0; - default: - return -EINVAL; - } - case SENSOR_CHAN_DIE_TEMP: - *shift = 9; - return 0; - default: - return -EINVAL; - } -} - -int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel chan, int32_t reading, - q31_t *out) -{ - int32_t whole; - int32_t fraction; - int64_t intermediate; - int8_t shift; - int rc; - - rc = icm42688_get_shift(chan, cfg->accel_fs, cfg->gyro_fs, &shift); - if (rc != 0) { - return rc; - } - - switch (chan) { - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - icm42688_accel_ms(cfg, reading, &whole, &fraction); - break; - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - icm42688_gyro_rads(cfg, reading, &whole, &fraction); - break; - case SENSOR_CHAN_DIE_TEMP: - icm42688_temp_c(reading, &whole, &fraction); - break; - default: - return -ENOTSUP; - } - intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); - if (shift < 0) { - intermediate = - intermediate * ((int64_t)INT32_MAX + 1) * (1 << -shift) / INT64_C(1000000); - } else if (shift > 0) { - intermediate = - intermediate * ((int64_t)INT32_MAX + 1) / ((1 << shift) * INT64_C(1000000)); - } - *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); - - return 0; -} - -static int icm42688_get_channel_position(enum sensor_channel chan) -{ - switch (chan) { - case SENSOR_CHAN_DIE_TEMP: - return 0; - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_ACCEL_X: - return 1; - case SENSOR_CHAN_ACCEL_Y: - return 2; - case SENSOR_CHAN_ACCEL_Z: - return 3; - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_GYRO_X: - return 4; - case SENSOR_CHAN_GYRO_Y: - return 5; - case SENSOR_CHAN_GYRO_Z: - return 6; - default: - return 0; - } -} - -static uint8_t icm42688_encode_channel(enum sensor_channel chan) -{ - uint8_t encode_bmask = 0; - - switch (chan) { - case SENSOR_CHAN_DIE_TEMP: - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - encode_bmask = BIT(icm42688_get_channel_position(chan)); - break; - case SENSOR_CHAN_ACCEL_XYZ: - encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_X)) | - BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Y)) | - BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Z)); - break; - case SENSOR_CHAN_GYRO_XYZ: - encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_X)) | - BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Y)) | - BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Z)); - break; - default: - break; - } - - return encode_bmask; -} - -int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *const channels, - const size_t num_channels, uint8_t *buf) -{ - struct icm42688_dev_data *data = dev->data; - struct icm42688_encoded_data *edata = (struct icm42688_encoded_data *)buf; - - edata->channels = 0; - - for (int i = 0; i < num_channels; i++) { - edata->channels |= icm42688_encode_channel(channels[i].chan_type); - } - - edata->header.is_fifo = false; - edata->header.accel_fs = data->cfg.accel_fs; - edata->header.gyro_fs = data->cfg.gyro_fs; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); - - return 0; -} - -#define IS_ACCEL(chan) ((chan) >= SENSOR_CHAN_ACCEL_X && (chan) <= SENSOR_CHAN_ACCEL_XYZ) -#define IS_GYRO(chan) ((chan) >= SENSOR_CHAN_GYRO_X && (chan) <= SENSOR_CHAN_GYRO_XYZ) - -static inline q31_t icm42688_read_temperature_from_packet(const uint8_t *pkt) -{ - int32_t temperature; - int32_t whole; - int32_t fraction; - - /* Temperature always assumes a shift of 9 for a range of (-273,273) C */ - if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { - temperature = (pkt[0xd] << 8) | pkt[0xe]; - - icm42688_temp_c(temperature, &whole, &fraction); - } else { - if (FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1 && - FIELD_GET(FIFO_HEADER_GYRO, pkt[0]) == 1) { - temperature = pkt[0xd]; - } else { - temperature = pkt[0x7]; - } - - int64_t sensitivity = 207; - int64_t temperature100 = (temperature * 100) + (25 * sensitivity); - - whole = temperature100 / sensitivity; - fraction = - ((temperature100 - whole * sensitivity) * INT64_C(1000000)) / sensitivity; - } - __ASSERT_NO_MSG(whole >= -512 && whole <= 511); - return FIELD_PREP(GENMASK(31, 22), whole) | (fraction * GENMASK64(21, 0) / 1000000); -} - -static int icm42688_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs, - uint8_t axis_offset, q31_t *out) -{ - int32_t value; - int64_t scale = 0; - int32_t max = BIT(15); - int offset = 1 + (axis_offset * 2); - - if (is_accel) { - switch (fs) { - case ICM42688_DT_ACCEL_FS_2: - scale = INT64_C(2) * BIT(31 - 5) * 9.80665; - break; - case ICM42688_DT_ACCEL_FS_4: - scale = INT64_C(4) * BIT(31 - 6) * 9.80665; - break; - case ICM42688_DT_ACCEL_FS_8: - scale = INT64_C(8) * BIT(31 - 7) * 9.80665; - break; - case ICM42688_DT_ACCEL_FS_16: - scale = INT64_C(16) * BIT(31 - 8) * 9.80665; - break; - } - } else { - switch (fs) { - case ICM42688_DT_GYRO_FS_2000: - scale = 164; - break; - case ICM42688_DT_GYRO_FS_1000: - scale = 328; - break; - case ICM42688_DT_GYRO_FS_500: - scale = 655; - break; - case ICM42688_DT_GYRO_FS_250: - scale = 1310; - break; - case ICM42688_DT_GYRO_FS_125: - scale = 2620; - break; - case ICM42688_DT_GYRO_FS_62_5: - scale = 5243; - break; - case ICM42688_DT_GYRO_FS_31_25: - scale = 10486; - break; - case ICM42688_DT_GYRO_FS_15_625: - scale = 20972; - break; - } - } - - if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) { - offset += 7; - } - - value = (int16_t)sys_le16_to_cpu((pkt[offset] << 8) | pkt[offset + 1]); - - if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { - uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0); - - offset = 0x11 + axis_offset; - value = (value << 4) | FIELD_GET(mask, pkt[offset]); - /* In 20 bit mode, FS can only be +/-16g and +/-2000dps */ - scale = is_accel ? (INT64_C(16) * BIT(8) * 9.80665) : 131; - max = is_accel ? BIT(18) : BIT(19); - if (value == -524288) { - /* Invalid 20 bit value */ - return -ENODATA; - } - } else { - if (value <= -32767) { - /* Invalid 16 bit value */ - return -ENODATA; - } - } - - *out = (q31_t)(value * scale / max); - return 0; -} - -static uint32_t accel_period_ns[] = { - [ICM42688_DT_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625, - [ICM42688_DT_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250, - [ICM42688_DT_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500, - [ICM42688_DT_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500, - [ICM42688_DT_ACCEL_ODR_25] = UINT32_C(1000000000) / 25, - [ICM42688_DT_ACCEL_ODR_50] = UINT32_C(1000000000) / 50, - [ICM42688_DT_ACCEL_ODR_100] = UINT32_C(1000000000) / 100, - [ICM42688_DT_ACCEL_ODR_200] = UINT32_C(1000000000) / 200, - [ICM42688_DT_ACCEL_ODR_500] = UINT32_C(1000000000) / 500, - [ICM42688_DT_ACCEL_ODR_1000] = UINT32_C(1000000), - [ICM42688_DT_ACCEL_ODR_2000] = UINT32_C(1000000) / 2, - [ICM42688_DT_ACCEL_ODR_4000] = UINT32_C(1000000) / 4, - [ICM42688_DT_ACCEL_ODR_8000] = UINT32_C(1000000) / 8, - [ICM42688_DT_ACCEL_ODR_16000] = UINT32_C(1000000) / 16, - [ICM42688_DT_ACCEL_ODR_32000] = UINT32_C(1000000) / 32, -}; - -static uint32_t gyro_period_ns[] = { - [ICM42688_DT_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500, - [ICM42688_DT_GYRO_ODR_25] = UINT32_C(1000000000) / 25, - [ICM42688_DT_GYRO_ODR_50] = UINT32_C(1000000000) / 50, - [ICM42688_DT_GYRO_ODR_100] = UINT32_C(1000000000) / 100, - [ICM42688_DT_GYRO_ODR_200] = UINT32_C(1000000000) / 200, - [ICM42688_DT_GYRO_ODR_500] = UINT32_C(1000000000) / 500, - [ICM42688_DT_GYRO_ODR_1000] = UINT32_C(1000000), - [ICM42688_DT_GYRO_ODR_2000] = UINT32_C(1000000) / 2, - [ICM42688_DT_GYRO_ODR_4000] = UINT32_C(1000000) / 4, - [ICM42688_DT_GYRO_ODR_8000] = UINT32_C(1000000) / 8, - [ICM42688_DT_GYRO_ODR_16000] = UINT32_C(1000000) / 16, - [ICM42688_DT_GYRO_ODR_32000] = UINT32_C(1000000) / 32, -}; - -static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, - uint32_t *fit, uint16_t max_count, void *data_out) -{ - const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; - const uint8_t *buffer_end = buffer + sizeof(struct icm42688_fifo_data) + edata->fifo_count; - int accel_frame_count = 0; - int gyro_frame_count = 0; - int count = 0; - int rc; - - if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) { - return 0; - } - - ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; - - buffer += sizeof(struct icm42688_fifo_data); - while (count < max_count && buffer < buffer_end) { - const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1; - const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1; - const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1; - const uint8_t *frame_end = buffer; - - if (is_20b) { - frame_end += 20; - } else if (has_accel && has_gyro) { - frame_end += 16; - } else { - frame_end += 8; - } - if (has_accel) { - accel_frame_count++; - } - if (has_gyro) { - gyro_frame_count++; - } - - if ((uintptr_t)buffer < *fit) { - /* This frame was already decoded, move on to the next frame */ - buffer = frame_end; - continue; - } - if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) { - struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; - - data->shift = 9; - if (has_accel) { - data->readings[count].timestamp_delta = - accel_period_ns[edata->accel_odr] * (accel_frame_count - 1); - } else { - data->readings[count].timestamp_delta = - gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1); - } - data->readings[count].temperature = - icm42688_read_temperature_from_packet(buffer); - } else if (IS_ACCEL(chan_spec.chan_type) && has_accel) { - /* Decode accel */ - struct sensor_three_axis_data *data = - (struct sensor_three_axis_data *)data_out; - uint64_t period_ns = accel_period_ns[edata->accel_odr]; - - icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs, - edata->header.gyro_fs, &data->shift); - - data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns; - rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0, - &data->readings[count].x); - rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1, - &data->readings[count].y); - rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2, - &data->readings[count].z); - if (rc != 0) { - accel_frame_count--; - buffer = frame_end; - continue; - } - } else if (IS_GYRO(chan_spec.chan_type) && has_gyro) { - /* Decode gyro */ - struct sensor_three_axis_data *data = - (struct sensor_three_axis_data *)data_out; - uint64_t period_ns = accel_period_ns[edata->gyro_odr]; - - icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs, - edata->header.gyro_fs, &data->shift); - - data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns; - rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0, - &data->readings[count].x); - rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1, - &data->readings[count].y); - rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2, - &data->readings[count].z); - if (rc != 0) { - gyro_frame_count--; - buffer = frame_end; - continue; - } - } - buffer = frame_end; - *fit = (uintptr_t)frame_end; - count++; - } - return count; -} - -static int icm42688_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, - uint32_t *fit, uint16_t max_count, void *data_out) -{ - const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer; - const struct icm42688_decoder_header *header = &edata->header; - struct icm42688_cfg cfg = { - .accel_fs = edata->header.accel_fs, - .gyro_fs = edata->header.gyro_fs, - }; - uint8_t channel_request; - int rc; - - if (*fit != 0) { - return 0; - } - if (max_count == 0 || chan_spec.chan_idx != 0) { - return -EINVAL; - } - - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: { - channel_request = icm42688_encode_channel(SENSOR_CHAN_ACCEL_XYZ); - if ((channel_request & edata->channels) != channel_request) { - return -ENODATA; - } - - struct sensor_three_axis_data *out = data_out; - - out->header.base_timestamp_ns = edata->header.timestamp; - out->header.reading_count = 1; - rc = icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs, header->gyro_fs, - &out->shift); - if (rc != 0) { - return -EINVAL; - } - - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_ACCEL_X, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_ACCEL_X)], - &out->readings[0].x); - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_ACCEL_Y, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Y)], - &out->readings[0].y); - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_ACCEL_Z, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Z)], - &out->readings[0].z); - *fit = 1; - return 1; - } - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: { - channel_request = icm42688_encode_channel(SENSOR_CHAN_GYRO_XYZ); - if ((channel_request & edata->channels) != channel_request) { - return -ENODATA; - } - - struct sensor_three_axis_data *out = data_out; - - out->header.base_timestamp_ns = edata->header.timestamp; - out->header.reading_count = 1; - rc = icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, header->accel_fs, header->gyro_fs, - &out->shift); - if (rc != 0) { - return -EINVAL; - } - - out->readings[0].timestamp_delta = 0; - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_GYRO_X, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_GYRO_X)], - &out->readings[0].x); - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_GYRO_Y, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_GYRO_Y)], - &out->readings[0].y); - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_GYRO_Z, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_GYRO_Z)], - &out->readings[0].z); - *fit = 1; - return 1; - } - case SENSOR_CHAN_DIE_TEMP: { - channel_request = icm42688_encode_channel(SENSOR_CHAN_DIE_TEMP); - if ((channel_request & edata->channels) != channel_request) { - return -ENODATA; - } - - struct sensor_q31_data *out = data_out; - - out->header.base_timestamp_ns = edata->header.timestamp; - out->header.reading_count = 1; - - rc = icm42688_get_shift(SENSOR_CHAN_DIE_TEMP, header->accel_fs, header->gyro_fs, - &out->shift); - if (rc != 0) { - return -EINVAL; - } - out->readings[0].timestamp_delta = 0; - icm42688_convert_raw_to_q31( - &cfg, SENSOR_CHAN_DIE_TEMP, - edata->readings[icm42688_get_channel_position(SENSOR_CHAN_DIE_TEMP)], - &out->readings[0].temperature); - *fit = 1; - return 1; - } - default: - return -EINVAL; - } -} - -static int icm42688_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, - uint32_t *fit, uint16_t max_count, void *data_out) -{ - const struct icm42688_decoder_header *header = - (const struct icm42688_decoder_header *)buffer; - - if (header->is_fifo) { - return icm42688_fifo_decode(buffer, chan_spec, fit, max_count, data_out); - } - return icm42688_one_shot_decode(buffer, chan_spec, fit, max_count, data_out); -} - -static int icm42688_decoder_get_frame_count(const uint8_t *buffer, - struct sensor_chan_spec chan_spec, - uint16_t *frame_count) -{ - const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer; - const struct icm42688_decoder_header *header = &data->header; - - if (chan_spec.chan_idx != 0) { - return -ENOTSUP; - } - - if (!header->is_fifo) { - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_DIE_TEMP: - *frame_count = 1; - return 0; - default: - return -ENOTSUP; - } - return 0; - } - - /* Skip the header */ - buffer += sizeof(struct icm42688_fifo_data); - - uint16_t count = 0; - const uint8_t *end = buffer + data->fifo_count; - - while (buffer < end) { - bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); - int size = is_20b ? 3 : 2; - - if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) { - size += 6; - } - if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) { - size += 6; - } - if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) { - size += 2; - } - if (is_20b) { - size += 3; - } - - buffer += size; - ++count; - } - - *frame_count = count; - return 0; -} - -static int icm42688_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, - size_t *frame_size) -{ - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - *base_size = sizeof(struct sensor_three_axis_data); - *frame_size = sizeof(struct sensor_three_axis_sample_data); - return 0; - case SENSOR_CHAN_DIE_TEMP: - *base_size = sizeof(struct sensor_q31_data); - *frame_size = sizeof(struct sensor_q31_sample_data); - return 0; - default: - return -ENOTSUP; - } -} - -static bool icm24688_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) -{ - const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; - - if (!edata->header.is_fifo) { - return false; - } - - switch (trigger) { - case SENSOR_TRIG_DATA_READY: - return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status); - case SENSOR_TRIG_FIFO_WATERMARK: - return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status); - case SENSOR_TRIG_FIFO_FULL: - return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status); - default: - return false; - } -} - -SENSOR_DECODER_API_DT_DEFINE() = { - .get_frame_count = icm42688_decoder_get_frame_count, - .get_size_info = icm42688_decoder_get_size_info, - .decode = icm42688_decoder_decode, - .has_trigger = icm24688_decoder_has_trigger, -}; - -int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) -{ - ARG_UNUSED(dev); - *decoder = &SENSOR_DECODER_NAME(); - - return 0; -} diff --git a/drivers/sensor/tdk/icm42688/icm42688_emul.c b/drivers/sensor/tdk/icm42688/icm42688_emul.c deleted file mode 100644 index 41b6b11ea5f24..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_emul.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT invensense_icm42688 - -#include -#include -#include -#include -#include -#include - -#include - -LOG_MODULE_DECLARE(ICM42688, CONFIG_SENSOR_LOG_LEVEL); - -#define NUM_REGS (UINT8_MAX >> 1) - -struct icm42688_emul_data { - uint8_t reg[NUM_REGS]; -}; - -struct icm42688_emul_cfg { -}; - -void icm42688_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val, - size_t count) -{ - struct icm42688_emul_data *data = target->data; - - __ASSERT_NO_MSG(reg_addr + count < NUM_REGS); - memcpy(data->reg + reg_addr, val, count); -} - -void icm42688_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val, size_t count) -{ - struct icm42688_emul_data *data = target->data; - - __ASSERT_NO_MSG(reg_addr + count < NUM_REGS); - memcpy(val, data->reg + reg_addr, count); -} - -static void icm42688_emul_handle_write(const struct emul *target, uint8_t regn, uint8_t value) -{ - struct icm42688_emul_data *data = target->data; - - switch (regn) { - case REG_DEVICE_CONFIG: - if (FIELD_GET(BIT_SOFT_RESET, value) == 1) { - /* Perform a soft reset */ - memset(data->reg, 0, NUM_REGS); - /* Initialized the who-am-i register */ - data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688; - /* Set the bit for the reset being done */ - data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_RESET_DONE; - } - break; - } -} - -static int icm42688_emul_io_spi(const struct emul *target, const struct spi_config *config, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) -{ - struct icm42688_emul_data *data = target->data; - const struct spi_buf *tx, *rx; - uint8_t regn; - bool is_read; - - ARG_UNUSED(config); - __ASSERT_NO_MSG(tx_bufs != NULL); - - tx = tx_bufs->buffers; - __ASSERT_NO_MSG(tx != NULL); - __ASSERT_NO_MSG(tx->len > 0); - - regn = *(uint8_t *)tx->buf; - is_read = FIELD_GET(REG_SPI_READ_BIT, regn); - regn &= GENMASK(6, 0); - if (is_read) { - __ASSERT_NO_MSG(rx_bufs != NULL); - __ASSERT_NO_MSG(rx_bufs->count > 1); - - rx = &rx_bufs->buffers[1]; - __ASSERT_NO_MSG(rx->buf != NULL); - __ASSERT_NO_MSG(rx->len > 0); - for (uint16_t i = 0; i < rx->len; ++i) { - ((uint8_t *)rx->buf)[i] = data->reg[regn + i]; - } - } else { - /* Writing to regn */ - uint8_t value; - - __ASSERT_NO_MSG(tx_bufs->count > 1); - tx = &tx_bufs->buffers[1]; - - __ASSERT_NO_MSG(tx->len > 0); - value = ((uint8_t *)tx->buf)[0]; - icm42688_emul_handle_write(target, regn, value); - } - - return 0; -} - -static int icm42688_emul_init(const struct emul *target, const struct device *parent) -{ - struct icm42688_emul_data *data = target->data; - - /* Initialized the who-am-i register */ - data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688; - - return 0; -} - -static const struct spi_emul_api icm42688_emul_spi_api = { - .io = icm42688_emul_io_spi, -}; - -#define Q31_SCALE ((int64_t)INT32_MAX + 1) - -/** - * @brief Get current full-scale range in g's based on register config, along with corresponding - * sensitivity and shift. See datasheet section 3.2, table 2. - */ -static void icm42688_emul_get_accel_settings(const struct emul *target, int *fs_g, int *sensitivity, - int8_t *shift) -{ - uint8_t reg; - - int sensitivity_out, fs_g_out; - int8_t shift_out; - - icm42688_emul_get_reg(target, REG_ACCEL_CONFIG0, ®, 1); - - switch ((reg & MASK_ACCEL_UI_FS_SEL) >> 5) { - case BIT_ACCEL_UI_FS_16: - fs_g_out = 16; - sensitivity_out = 2048; - /* shift is based on `fs_g * 9.8` since the final numbers will be in SI units of - * m/s^2, not g's - */ - shift_out = 8; - break; - case BIT_ACCEL_UI_FS_8: - fs_g_out = 8; - sensitivity_out = 4096; - shift_out = 7; - break; - case BIT_ACCEL_UI_FS_4: - fs_g_out = 4; - sensitivity_out = 8192; - shift_out = 6; - break; - case BIT_ACCEL_UI_FS_2: - fs_g_out = 2; - sensitivity_out = 16384; - shift_out = 5; - break; - default: - __ASSERT_UNREACHABLE; - } - - if (fs_g) { - *fs_g = fs_g_out; - } - if (sensitivity) { - *sensitivity = sensitivity_out; - } - if (shift) { - *shift = shift_out; - } -} - -/** - * @brief Helper function for calculating accelerometer ranges. Considers the current full-scale - * register config (i.e. +/-2g, +/-4g, etc...) - */ -static void icm42688_emul_get_accel_ranges(const struct emul *target, q31_t *lower, q31_t *upper, - q31_t *epsilon, int8_t *shift) -{ - int fs_g; - int sensitivity; - - icm42688_emul_get_accel_settings(target, &fs_g, &sensitivity, shift); - - /* Epsilon is equal to 1.5 bit-counts worth of error. */ - *epsilon = (3 * SENSOR_G * Q31_SCALE / sensitivity / 1000000LL / 2) >> *shift; - *upper = (fs_g * SENSOR_G * Q31_SCALE / 1000000LL) >> *shift; - *lower = -*upper; -} - -/** - * @brief Get current full-scale gyro range in milli-degrees per second based on register config, - * along with corresponding sensitivity and shift. See datasheet section 3.1, table 1. - */ -static void icm42688_emul_get_gyro_settings(const struct emul *target, int *fs_mdps, - int *sensitivity, int8_t *shift) -{ - uint8_t reg; - - int sensitivity_out, fs_mdps_out; - int8_t shift_out; - - icm42688_emul_get_reg(target, REG_GYRO_CONFIG0, ®, 1); - - switch ((reg & MASK_GYRO_UI_FS_SEL) >> 5) { - case BIT_GYRO_UI_FS_2000: - /* Milli-degrees per second */ - fs_mdps_out = 2000000; - /* 10x LSBs/deg/s */ - sensitivity_out = 164; - /* Shifts are based on rad/s: `(fs_mdps * pi / 180 / 1000)` */ - shift_out = 6; /* +/- 34.90659 */ - break; - case BIT_GYRO_UI_FS_1000: - fs_mdps_out = 1000000; - sensitivity_out = 328; - shift_out = 5; /* +/- 17.44444 */ - break; - case BIT_GYRO_UI_FS_500: - fs_mdps_out = 500000; - sensitivity_out = 655; - shift_out = 4; /* +/- 8.72222 */ - break; - case BIT_GYRO_UI_FS_250: - fs_mdps_out = 250000; - sensitivity_out = 1310; - shift_out = 3; /* +/- 4.36111 */ - break; - case BIT_GYRO_UI_FS_125: - fs_mdps_out = 125000; - sensitivity_out = 2620; - shift_out = 2; /* +/- 2.18055 */ - break; - case BIT_GYRO_UI_FS_62_5: - fs_mdps_out = 62500; - sensitivity_out = 5243; - shift_out = 1; /* +/- 1.09027 */ - break; - case BIT_GYRO_UI_FS_31_25: - fs_mdps_out = 31250; - sensitivity_out = 10486; - shift_out = 0; /* +/- 0.54513 */ - break; - case BIT_GYRO_UI_FS_15_625: - fs_mdps_out = 15625; - sensitivity_out = 20972; - shift_out = -1; /* +/- 0.27256 */ - break; - default: - __ASSERT_UNREACHABLE; - } - - if (fs_mdps) { - *fs_mdps = fs_mdps_out; - } - if (sensitivity) { - *sensitivity = sensitivity_out; - } - if (shift) { - *shift = shift_out; - } -} - -/** - * @brief Helper function for calculating gyroscope ranges. Considers the current full-scale - * register config - */ -static void icm42688_emul_get_gyro_ranges(const struct emul *target, q31_t *lower, q31_t *upper, - q31_t *epsilon, int8_t *shift) -{ - /* millidegrees/second */ - int fs_mdps; - /* 10x LSBs per degrees/second*/ - int sensitivity; - - icm42688_emul_get_gyro_settings(target, &fs_mdps, &sensitivity, shift); - - /* Reduce the actual range of gyroscope values. Some full-scale ranges actually exceed the - * size of an int16 by a small margin. For example, FS_SEL=0 has a +/-2000 deg/s range with - * 16.4 bits/deg/s sensitivity (Section 3.1, Table 1). This works out to register values of - * +/-2000 * 16.4 = +/-32800. This will cause the expected value to get clipped when - * setting the register and throw off the actual reading. Therefore, scale down the range - * to 99% to avoid the top and bottom edges. - */ - - fs_mdps *= 0.99; - - /* Epsilon is equal to 1.5 bit-counts worth of error. */ - *epsilon = (3 * SENSOR_PI * Q31_SCALE * 10LL / 1000000LL / 180LL / sensitivity / 2LL) >> - *shift; - *upper = (((fs_mdps * SENSOR_PI / 1000000LL) * Q31_SCALE) / 1000LL / 180LL) >> *shift; - *lower = -*upper; -} - -static int icm42688_emul_backend_get_sample_range(const struct emul *target, - struct sensor_chan_spec ch, q31_t *lower, - q31_t *upper, q31_t *epsilon, int8_t *shift) -{ - if (!lower || !upper || !epsilon || !shift) { - return -EINVAL; - } - - switch (ch.chan_type) { - case SENSOR_CHAN_DIE_TEMP: - /* degrees C = ([16-bit signed temp_data register] / 132.48) + 25 */ - *shift = 9; - *lower = (int64_t)(-222.342995169 * Q31_SCALE) >> *shift; - *upper = (int64_t)(272.33544686 * Q31_SCALE) >> *shift; - *epsilon = (int64_t)(0.0076 * Q31_SCALE) >> *shift; - break; - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - icm42688_emul_get_accel_ranges(target, lower, upper, epsilon, shift); - break; - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - icm42688_emul_get_gyro_ranges(target, lower, upper, epsilon, shift); - break; - default: - return -ENOTSUP; - } - - return 0; -} - -static int icm42688_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, - const q31_t *value, int8_t shift) -{ - if (!target || !target->data) { - return -EINVAL; - } - - struct icm42688_emul_data *data = target->data; - - int sensitivity; - uint8_t reg_addr; - int32_t reg_val; - int64_t value_unshifted = - shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); - - switch (ch.chan_type) { - case SENSOR_CHAN_DIE_TEMP: - reg_addr = REG_TEMP_DATA1; - reg_val = ((value_unshifted - (25 * Q31_SCALE)) * 13248) / (100 * Q31_SCALE); - break; - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - switch (ch.chan_type) { - case SENSOR_CHAN_ACCEL_X: - reg_addr = REG_ACCEL_DATA_X1; - break; - case SENSOR_CHAN_ACCEL_Y: - reg_addr = REG_ACCEL_DATA_Y1; - break; - case SENSOR_CHAN_ACCEL_Z: - reg_addr = REG_ACCEL_DATA_Z1; - break; - default: - __ASSERT_UNREACHABLE; - } - icm42688_emul_get_accel_settings(target, NULL, &sensitivity, NULL); - reg_val = ((value_unshifted * sensitivity / Q31_SCALE) * 1000000LL) / SENSOR_G; - break; - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - switch (ch.chan_type) { - case SENSOR_CHAN_GYRO_X: - reg_addr = REG_GYRO_DATA_X1; - break; - case SENSOR_CHAN_GYRO_Y: - reg_addr = REG_GYRO_DATA_Y1; - break; - case SENSOR_CHAN_GYRO_Z: - reg_addr = REG_GYRO_DATA_Z1; - break; - default: - __ASSERT_UNREACHABLE; - } - icm42688_emul_get_gyro_settings(target, NULL, &sensitivity, NULL); - reg_val = - CLAMP((((value_unshifted * sensitivity * 180LL) / Q31_SCALE) * 1000000LL) / - SENSOR_PI / 10LL, - INT16_MIN, INT16_MAX); - break; - default: - return -ENOTSUP; - } - - data->reg[reg_addr] = (reg_val >> 8) & 0xFF; - data->reg[reg_addr + 1] = reg_val & 0xFF; - - /* Set data ready flag */ - data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_DATA_RDY; - - return 0; -} - -static const struct emul_sensor_driver_api icm42688_emul_sensor_driver_api = { - .set_channel = icm42688_emul_backend_set_channel, - .get_sample_range = icm42688_emul_backend_get_sample_range, -}; - -#define ICM42688_EMUL_DEFINE(n, api) \ - EMUL_DT_INST_DEFINE(n, icm42688_emul_init, &icm42688_emul_data_##n, \ - &icm42688_emul_cfg_##n, &api, &icm42688_emul_sensor_driver_api) - -#define ICM42688_EMUL_SPI(n) \ - static struct icm42688_emul_data icm42688_emul_data_##n; \ - static const struct icm42688_emul_cfg icm42688_emul_cfg_##n; \ - ICM42688_EMUL_DEFINE(n, icm42688_emul_spi_api) - -DT_INST_FOREACH_STATUS_OKAY(ICM42688_EMUL_SPI) diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio.h b/drivers/sensor/tdk/icm42688/icm42688_rtio.h deleted file mode 100644 index a4d12b82a1891..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2023 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ - -#include -#include - -void icm42688_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); - -void icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); - -void icm42688_fifo_event(const struct device *dev); - -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_trigger.c b/drivers/sensor/tdk/icm42688/icm42688_trigger.c deleted file mode 100644 index 72ccd7e9059e4..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_trigger.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -#include "icm42688.h" -#include "icm42688_reg.h" -#include "icm42688_rtio.h" -#include "icm42688_spi.h" -#include "icm42688_trigger.h" - -LOG_MODULE_DECLARE(ICM42688, CONFIG_SENSOR_LOG_LEVEL); - -static void icm42688_gpio_callback(const struct device *dev, struct gpio_callback *cb, - uint32_t pins) -{ - struct icm42688_dev_data *data = CONTAINER_OF(cb, struct icm42688_dev_data, gpio_cb); - - ARG_UNUSED(dev); - ARG_UNUSED(pins); - -#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) - k_sem_give(&data->gpio_sem); -#elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) - k_work_submit(&data->work); -#endif - if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { - icm42688_fifo_event(data->dev); - } -} - -#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) -static void icm42688_thread_cb(const struct device *dev) -{ - struct icm42688_dev_data *data = dev->data; - - icm42688_lock(dev); - - if (data->data_ready_handler != NULL) { - data->data_ready_handler(dev, data->data_ready_trigger); - } - - icm42688_unlock(dev); -} -#endif - -#ifdef CONFIG_ICM42688_TRIGGER_OWN_THREAD - -static void icm42688_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - struct icm42688_dev_data *data = p1; - - while (1) { - k_sem_take(&data->gpio_sem, K_FOREVER); - icm42688_thread_cb(data->dev); - } -} - -#elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) - -static void icm42688_work_handler(struct k_work *work) -{ - struct icm42688_dev_data *data = CONTAINER_OF(work, struct icm42688_dev_data, work); - - icm42688_thread_cb(data->dev); -} - -#endif - -int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger *trig, - sensor_trigger_handler_t handler) -{ - struct icm42688_dev_data *data = dev->data; - const struct icm42688_dev_cfg *cfg = dev->config; - uint8_t status; - int res = 0; - - if (trig == NULL || handler == NULL) { - return -EINVAL; - } - - icm42688_lock(dev); - gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_DISABLE); - - switch (trig->type) { - case SENSOR_TRIG_DATA_READY: - case SENSOR_TRIG_FIFO_WATERMARK: - case SENSOR_TRIG_FIFO_FULL: - data->data_ready_handler = handler; - data->data_ready_trigger = trig; - - res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); - break; - default: - res = -ENOTSUP; - break; - } - - icm42688_unlock(dev); - gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); - - return res; -} - -int icm42688_trigger_init(const struct device *dev) -{ - struct icm42688_dev_data *data = dev->data; - const struct icm42688_dev_cfg *cfg = dev->config; - int res = 0; - - if (!cfg->gpio_int1.port) { - LOG_ERR("trigger enabled but no interrupt gpio supplied"); - return -ENODEV; - } - - if (!gpio_is_ready_dt(&cfg->gpio_int1)) { - LOG_ERR("gpio_int1 not ready"); - return -ENODEV; - } - - data->dev = dev; - gpio_pin_configure_dt(&cfg->gpio_int1, GPIO_INPUT); - gpio_init_callback(&data->gpio_cb, icm42688_gpio_callback, BIT(cfg->gpio_int1.pin)); - res = gpio_add_callback(cfg->gpio_int1.port, &data->gpio_cb); - - if (res < 0) { - LOG_ERR("Failed to set gpio callback"); - return res; - } - - k_mutex_init(&data->mutex); -#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) - k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT); - k_thread_create(&data->thread, data->thread_stack, CONFIG_ICM42688_THREAD_STACK_SIZE, - icm42688_thread, data, NULL, NULL, - K_PRIO_COOP(CONFIG_ICM42688_THREAD_PRIORITY), 0, K_NO_WAIT); -#elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) - data->work.handler = icm42688_work_handler; -#endif - return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); -} - -int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg) -{ - int res; - const struct icm42688_dev_cfg *cfg = dev->config; - - /* pulse-mode (auto clearing), push-pull and active-high */ - res = icm42688_spi_single_write(&cfg->spi, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); - if (res != 0) { - return res; - } - - /* Deassert async reset for proper INT pin operation, see datasheet 14.50 */ - res = icm42688_spi_single_write(&cfg->spi, REG_INT_CONFIG1, 0); - if (res != 0) { - return res; - } - - /* enable interrupts on INT1 pin */ - uint8_t value = 0; - - if (new_cfg->interrupt1_drdy) { - value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1); - } - if (new_cfg->interrupt1_fifo_ths) { - value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1); - } - if (new_cfg->interrupt1_fifo_full) { - value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1); - } - return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value); -} - -void icm42688_lock(const struct device *dev) -{ - struct icm42688_dev_data *data = dev->data; - - k_mutex_lock(&data->mutex, K_FOREVER); -} - -void icm42688_unlock(const struct device *dev) -{ - struct icm42688_dev_data *data = dev->data; - - k_mutex_unlock(&data->mutex); -} diff --git a/drivers/sensor/tdk/icm42688/icm42688_trigger.h b/drivers/sensor/tdk/icm42688/icm42688_trigger.h deleted file mode 100644 index e039759161812..0000000000000 --- a/drivers/sensor/tdk/icm42688/icm42688_trigger.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2023 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_TRIGGER_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_TRIGGER_H_ - -#include - -/** implement the trigger_set sensor api function */ -int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger *trig, - sensor_trigger_handler_t handler); - -/** - * @brief initialize the icm42688 trigger system - * - * @param dev icm42688 device pointer - * @return int 0 on success, negative error code otherwise - */ -int icm42688_trigger_init(const struct device *dev); - -/** - * @brief enable the trigger gpio interrupt - * - * @param dev icm42688 device pointer - * @param new_cfg New configuration to use for the device - * @return int 0 on success, negative error code otherwise - */ -int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg); - -/** - * @brief lock access to the icm42688 device driver - * - * @param dev icm42688 device pointer - */ -void icm42688_lock(const struct device *dev); - -/** - * @brief lock access to the icm42688 device driver - * - * @param dev icm42688 device pointer - */ -void icm42688_unlock(const struct device *dev); - -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_TRIGGER_H_ */ diff --git a/drivers/sensor/tdk/icm4268x/CMakeLists.txt b/drivers/sensor/tdk/icm4268x/CMakeLists.txt new file mode 100644 index 0000000000000..76a814f2baa81 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + icm4268x.c + icm4268x_common.c + icm4268x_spi.c +) + +zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm4268x_rtio.c) +zephyr_library_sources_ifdef(CONFIG_ICM4268X_DECODER icm4268x_decoder.c) +zephyr_library_sources_ifdef(CONFIG_ICM4268X_STREAM icm4268x_rtio_stream.c) +zephyr_library_sources_ifdef(CONFIG_ICM4268X_TRIGGER icm4268x_trigger.c) +zephyr_library_sources_ifdef(CONFIG_EMUL_ICM4268X icm4268x_emul.c) +zephyr_include_directories_ifdef(CONFIG_EMUL_ICM4268X .) diff --git a/drivers/sensor/tdk/icm4268x/Kconfig b/drivers/sensor/tdk/icm4268x/Kconfig new file mode 100644 index 0000000000000..7dd6edbc7d323 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/Kconfig @@ -0,0 +1,81 @@ +# ICM4268X-P Six-Axis Motion Tracking device configuration options +# +# Copyright (c) 2022 Intel Corporation +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ICM4268X + bool "ICM4268X Six-Axis Motion Tracking Device" + default y + depends on DT_HAS_INVENSENSE_ICM42688_ENABLED + select SPI + help + Enable driver for ICM4268X SPI-based six-axis motion tracking device. + +if ICM4268X + +config EMUL_ICM4268X + bool "Emulator for the ICM4268X" + default y + depends on EMUL + help + Enable the hardware emulator for the ICM4268X. Doing so allows exercising + sensor APIs for this IMU in native_sim and qemu. + +config ICM4268X_DECODER + bool "ICM4268X decoder logic" + default y + select SENSOR_ASYNC_API + help + Compile the ICM4268X decoder API which allows decoding raw data returned + from the sensor. + +choice + prompt "Trigger mode" + default ICM4268X_TRIGGER_NONE if ICM4268X_STREAM + default ICM4268X_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver + +config ICM4268X_TRIGGER_NONE + bool "No trigger" + +config ICM4268X_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + select ICM4268X_TRIGGER + +config ICM4268X_TRIGGER_OWN_THREAD + bool "Use own thread" + select ICM4268X_TRIGGER + +endchoice + +config ICM4268X_STREAM + bool "Use hardware FIFO to stream data" + select ICM4268X_TRIGGER + default y + depends on SPI_RTIO + depends on SENSOR_ASYNC_API + help + Use this config option to enable streaming sensor data via RTIO subsystem. + +config ICM4268X_TRIGGER + bool + +config ICM4268X_THREAD_PRIORITY + int "Own thread priority" + depends on ICM4268X_TRIGGER_OWN_THREAD + default 10 + help + The priority of the thread used for handling interrupts. + +config ICM4268X_THREAD_STACK_SIZE + int "Own thread stack size" + depends on ICM4268X_TRIGGER_OWN_THREAD + default 1024 + help + The thread stack size. + +endif # ICM4268X diff --git a/drivers/sensor/tdk/icm4268x/icm4268x.c b/drivers/sensor/tdk/icm4268x/icm4268x.c new file mode 100644 index 0000000000000..42a66abb12106 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2022 Esco Medical ApS + * Copyright (c) 2020 TDK Invensense + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "icm4268x.h" +#include "icm4268x_decoder.h" +#include "icm4268x_reg.h" +#include "icm4268x_rtio.h" +#include "icm4268x_spi.h" +#include "icm4268x_trigger.h" + +#include +LOG_MODULE_REGISTER(ICM4268X, CONFIG_SENSOR_LOG_LEVEL); + +static void icm4268x_convert_accel(struct sensor_value *val, int16_t raw_val, + struct icm4268x_cfg *cfg) +{ + if (cfg->dev_id == WHO_AM_I_ICM42686) + icm42686_accel_ms(cfg, (int32_t)raw_val, &val->val1, &val->val2); + else + icm42688_accel_ms(cfg, (int32_t)raw_val, &val->val1, &val->val2); +} + +static void icm4268x_convert_gyro(struct sensor_value *val, int16_t raw_val, + struct icm4268x_cfg *cfg) +{ + if (cfg->dev_id == WHO_AM_I_ICM42686) + icm42686_gyro_rads(cfg, (int32_t)raw_val, &val->val1, &val->val2); + else + icm42688_gyro_rads(cfg, (int32_t)raw_val, &val->val1, &val->val2); +} + +static inline void icm4268x_convert_temp(struct sensor_value *val, int16_t raw_val) +{ + icm4268x_temp_c((int32_t)raw_val, &val->val1, &val->val2); +} + +int icm4268x_channel_parse_readings(enum sensor_channel chan, int16_t readings[7], + struct icm4268x_cfg *cfg, struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + icm4268x_convert_accel(&val[0], readings[1], cfg); + icm4268x_convert_accel(&val[1], readings[2], cfg); + icm4268x_convert_accel(&val[2], readings[3], cfg); + break; + case SENSOR_CHAN_ACCEL_X: + icm4268x_convert_accel(val, readings[1], cfg); + break; + case SENSOR_CHAN_ACCEL_Y: + icm4268x_convert_accel(val, readings[2], cfg); + break; + case SENSOR_CHAN_ACCEL_Z: + icm4268x_convert_accel(val, readings[3], cfg); + break; + case SENSOR_CHAN_GYRO_XYZ: + icm4268x_convert_gyro(&val[0], readings[4], cfg); + icm4268x_convert_gyro(&val[1], readings[5], cfg); + icm4268x_convert_gyro(&val[2], readings[6], cfg); + break; + case SENSOR_CHAN_GYRO_X: + icm4268x_convert_gyro(val, readings[4], cfg); + break; + case SENSOR_CHAN_GYRO_Y: + icm4268x_convert_gyro(val, readings[5], cfg); + break; + case SENSOR_CHAN_GYRO_Z: + icm4268x_convert_gyro(val, readings[6], cfg); + break; + case SENSOR_CHAN_DIE_TEMP: + icm4268x_convert_temp(val, readings[0]); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int icm4268x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct icm4268x_dev_data *data = dev->data; + + return icm4268x_channel_parse_readings(chan, data->readings, &data->cfg, val); +} + +static int icm4268x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + uint8_t status; + struct icm4268x_dev_data *data = dev->data; + const struct icm4268x_dev_cfg *cfg = dev->config; + + int res = icm4268x_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); + + if (res) { + return res; + } + + if (!FIELD_GET(BIT_INT_STATUS_DATA_RDY, status)) { + return -EBUSY; + } + + uint8_t readings[14]; + + res = icm4268x_read_all(dev, readings); + + if (res) { + return res; + } + + for (int i = 0; i < 7; i++) { + data->readings[i] = sys_le16_to_cpu((readings[i * 2] << 8) | readings[i * 2 + 1]); + } + + return 0; +} + +static int icm4268x_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + const struct icm4268x_dev_data *data = dev->data; + struct icm4268x_cfg new_config = data->cfg; + int res = 0; + + __ASSERT_NO_MSG(val != NULL); + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + new_config.accel_odr = icm4268x_accel_hz_to_reg(val->val1); + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + if (new_config.dev_id == WHO_AM_I_ICM42686) { + new_config.accel_fs = + icm42686_accel_fs_to_reg(sensor_ms2_to_g(val)); + } else if (new_config.dev_id == WHO_AM_I_ICM42688) { + new_config.accel_fs = + icm42688_accel_fs_to_reg(sensor_ms2_to_g(val)); + } + } else { + LOG_ERR("Unsupported attribute"); + res = -ENOTSUP; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + new_config.gyro_odr = icm4268x_gyro_odr_to_reg(val->val1); + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + if (new_config.dev_id == WHO_AM_I_ICM42686) { + new_config.gyro_fs = + icm42686_gyro_fs_to_reg(sensor_rad_to_degrees(val)); + } else if (new_config.dev_id == WHO_AM_I_ICM42688) { + new_config.gyro_fs = + icm42688_gyro_fs_to_reg(sensor_rad_to_degrees(val)); + } + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_BATCH_DURATION) { + if (val->val1 < 0) { + return -EINVAL; + } + new_config.batch_ticks = val->val1; + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; + default: + LOG_ERR("Unsupported channel"); + res = -EINVAL; + break; + } + + if (res) { + return res; + } + return icm4268x_safely_configure(dev, &new_config); +} + +static int icm4268x_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + const struct icm4268x_dev_data *data = dev->data; + const struct icm4268x_cfg *cfg = &data->cfg; + int res = 0; + + __ASSERT_NO_MSG(val != NULL); + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + icm4268x_accel_reg_to_hz(cfg->accel_odr, val); + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + if (cfg->dev_id == WHO_AM_I_ICM42686) { + icm42686_accel_reg_to_fs(cfg->accel_fs, val); + } else if (cfg->dev_id == WHO_AM_I_ICM42688) { + icm42688_accel_reg_to_fs(cfg->accel_fs, val); + } + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + icm4268x_gyro_reg_to_odr(cfg->gyro_odr, val); + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + if (cfg->dev_id == WHO_AM_I_ICM42686) { + icm42686_gyro_reg_to_fs(cfg->gyro_fs, val); + } else if (cfg->dev_id == WHO_AM_I_ICM42688) { + icm42688_gyro_reg_to_fs(cfg->gyro_fs, val); + } + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_BATCH_DURATION) { + val->val1 = cfg->batch_ticks; + val->val2 = 0; + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; + default: + LOG_ERR("Unsupported channel"); + res = -EINVAL; + break; + } + + return res; +} + +static const struct sensor_driver_api icm4268x_driver_api = { + .sample_fetch = icm4268x_sample_fetch, + .channel_get = icm4268x_channel_get, + .attr_set = icm4268x_attr_set, + .attr_get = icm4268x_attr_get, +#ifdef CONFIG_ICM4268X_TRIGGER + .trigger_set = icm4268x_trigger_set, +#endif + .get_decoder = icm4268x_get_decoder, +#ifdef CONFIG_SENSOR_ASYNC_API + .submit = icm4268x_submit, +#endif +}; + +int icm4268x_init(const struct device *dev) +{ + struct icm4268x_dev_data *data = dev->data; + const struct icm4268x_dev_cfg *cfg = dev->config; + int res; + + if (!spi_is_ready_dt(&cfg->spi)) { + LOG_ERR("SPI bus is not ready"); + return -ENODEV; + } + + if (icm4268x_reset(dev)) { + LOG_ERR("could not initialize sensor"); + return -EIO; + } + +#ifdef CONFIG_ICM4268X_TRIGGER + res = icm4268x_trigger_init(dev); + if (res != 0) { + LOG_ERR("Failed to initialize triggers"); + return res; + } +#endif + + res = icm4268x_configure(dev, &data->cfg); + if (res != 0) { + LOG_ERR("Failed to configure"); + return res; + } + + return 0; +} + +#ifndef CONFIG_ICM4268X_TRIGGER +void icm4268x_lock(const struct device *dev) +{ + ARG_UNUSED(dev); +} +void icm4268x_unlock(const struct device *dev) +{ + ARG_UNUSED(dev); +} +#endif + +/* device defaults to spi mode 0/3 support */ +#define ICM4268X_SPI_CFG \ + SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB + +#define ICM4268X_RTIO_DEFINE(name, inst) \ + SPI_DT_IODEV_DEFINE(name##_spi_iodev_##inst, DT_DRV_INST(inst), ICM4268X_SPI_CFG, 0U); \ + RTIO_DEFINE(name##_rtio_##inst, 8, 4); + +#define ICM4268X_DT_CONFIG_INIT(inst, who_am_i) \ + { \ + .dev_id = who_am_i, \ + .accel_pwr_mode = DT_INST_PROP(inst, accel_pwr_mode), \ + .accel_fs = DT_INST_PROP(inst, accel_fs), \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .aaf_cfg[AAF_ACCEL_IDX].aaf_delt = DT_INST_PROP(inst, accel_aaf_bw), \ + .aaf_cfg[AAF_GYRO_IDX].aaf_delt = DT_INST_PROP(inst, gyro_aaf_bw), \ + .gyro_pwr_mode = DT_INST_PROP(inst, gyro_pwr_mode), \ + .gyro_fs = DT_INST_PROP(inst, gyro_fs), \ + .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ + .temp_dis = false, \ + .fifo_en = IS_ENABLED(CONFIG_ICM4268X_STREAM), \ + .tmst_dis = DT_INST_PROP(inst, tmst_dis), \ + .tmst_fsync_en = DT_INST_PROP(inst, tmst_fsync_en), \ + .tmst_delta_en = DT_INST_PROP(inst, tmst_delta_en), \ + .tmst_res = DT_INST_PROP(inst, tmst_res), \ + .tmst_regs_en = DT_INST_PROP(inst, tmst_regs_en), \ + .fifo_mode = DT_INST_PROP(inst, fifo_mode), \ + .fifo_ths_int_clr = DT_INST_PROP(inst, fifo_ths_int_clr), \ + .fifo_full_int_clr = DT_INST_PROP(inst, fifo_full_int_clr), \ + .batch_ticks = 0, \ + .fifo_hires = false, \ + .int1_mode = DT_INST_PROP(inst, int1_mode), \ + .int1_pol = DT_INST_PROP(inst, int1_pol), \ + .interrupt1_drdy = false, \ + .interrupt1_fifo_ths = false, \ + .interrupt1_fifo_full = false \ + } + +#define ICM4268X_DEFINE_DATA(inst, name, who_am_i) \ + IF_ENABLED(CONFIG_ICM4268X_STREAM, (ICM4268X_RTIO_DEFINE(name, inst))); \ + static struct icm4268x_dev_data name##_driver_##inst = { \ + .cfg = ICM4268X_DT_CONFIG_INIT(inst, who_am_i), \ + IF_ENABLED(CONFIG_ICM4268X_STREAM, (.r = &name##_rtio_##inst, \ + .spi_iodev = &name##_spi_iodev_##inst,)) \ + }; + +#define ICM4268X_INIT(inst, name, who_am_i) \ + ICM4268X_DEFINE_DATA(inst, name, who_am_i); \ + \ + static const struct icm4268x_dev_cfg name##_cfg_##inst = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, ICM4268X_SPI_CFG, 0U), \ + .gpio_int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, icm4268x_init, NULL, &name##_driver_##inst, \ + &name##_cfg_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &icm4268x_driver_api); + +#define ICM42688_INIT(inst) \ + ICM4268X_INIT(inst, icm42688, WHO_AM_I_ICM42688) + +#define ICM42686_INIT(inst) \ + ICM4268X_INIT(inst, icm42686, WHO_AM_I_ICM42686) + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42688 +DT_INST_FOREACH_STATUS_OKAY(ICM42688_INIT) + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42686 +DT_INST_FOREACH_STATUS_OKAY(ICM42686_INIT) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x.h b/drivers/sensor/tdk/icm4268x/icm4268x.h new file mode 100644 index 0000000000000..bb1188e28ec67 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_H_ + +#include +#include +#include +#include +#include +#include + +/* ICM4268x parts support 63 AAF Bandwidths */ +#define AAF_BW_MAX_IDX 63 + +/* AAF is for 2 sensors Accel & Gyro */ +#define AAF_SENSORS_NUM 2 +#define AAF_ACCEL_IDX 0 +#define AAF_GYRO_IDX 1 + +static inline uint8_t icm42686_accel_fs_to_reg(uint8_t g) +{ + if (g >= 32) { + return ICM42686_DT_ACCEL_FS_32; + } else if (g >= 16) { + return ICM42686_DT_ACCEL_FS_16; + } else if (g >= 8) { + return ICM42686_DT_ACCEL_FS_8; + } else if (g >= 4) { + return ICM42686_DT_ACCEL_FS_4; + } else { + return ICM42686_DT_ACCEL_FS_2; + } +} + +static inline uint8_t icm42688_accel_fs_to_reg(uint8_t g) +{ + if (g >= 16) { + return ICM42688_DT_ACCEL_FS_16; + } else if (g >= 8) { + return ICM42688_DT_ACCEL_FS_8; + } else if (g >= 4) { + return ICM42688_DT_ACCEL_FS_4; + } else { + return ICM42688_DT_ACCEL_FS_2; + } +} + +static inline void icm42686_accel_reg_to_fs(uint8_t fs, struct sensor_value *out) +{ + switch (fs) { + case ICM42686_DT_ACCEL_FS_32: + sensor_g_to_ms2(32, out); + return; + case ICM42686_DT_ACCEL_FS_16: + sensor_g_to_ms2(16, out); + return; + case ICM42686_DT_ACCEL_FS_8: + sensor_g_to_ms2(8, out); + return; + case ICM42686_DT_ACCEL_FS_4: + sensor_g_to_ms2(4, out); + return; + case ICM42686_DT_ACCEL_FS_2: + sensor_g_to_ms2(2, out); + return; + } +} + +static inline void icm42688_accel_reg_to_fs(uint8_t fs, struct sensor_value *out) +{ + switch (fs) { + case ICM42688_DT_ACCEL_FS_16: + sensor_g_to_ms2(16, out); + return; + case ICM42688_DT_ACCEL_FS_8: + sensor_g_to_ms2(8, out); + return; + case ICM42688_DT_ACCEL_FS_4: + sensor_g_to_ms2(4, out); + return; + case ICM42688_DT_ACCEL_FS_2: + sensor_g_to_ms2(2, out); + return; + } +} + +static inline uint8_t icm42686_gyro_fs_to_reg(uint16_t dps) +{ + if (dps >= 4000) { + return ICM42686_DT_GYRO_FS_4000; + } else if (dps >= 2000) { + return ICM42686_DT_GYRO_FS_2000; + } else if (dps >= 1000) { + return ICM42686_DT_GYRO_FS_1000; + } else if (dps >= 500) { + return ICM42686_DT_GYRO_FS_500; + } else if (dps >= 250) { + return ICM42686_DT_GYRO_FS_250; + } else if (dps >= 125) { + return ICM42686_DT_GYRO_FS_125; + } else if (dps >= 62) { + return ICM42686_DT_GYRO_FS_62_5; + } else { + return ICM42686_DT_GYRO_FS_31_25; + } +} + +static inline uint8_t icm42688_gyro_fs_to_reg(uint16_t dps) +{ + if (dps >= 2000) { + return ICM42688_DT_GYRO_FS_2000; + } else if (dps >= 1000) { + return ICM42688_DT_GYRO_FS_1000; + } else if (dps >= 500) { + return ICM42688_DT_GYRO_FS_500; + } else if (dps >= 250) { + return ICM42688_DT_GYRO_FS_250; + } else if (dps >= 125) { + return ICM42688_DT_GYRO_FS_125; + } else if (dps >= 62) { + return ICM42688_DT_GYRO_FS_62_5; + } else if (dps >= 31) { + return ICM42688_DT_GYRO_FS_31_25; + } else { + return ICM42688_DT_GYRO_FS_15_625; + } +} + +static inline void icm42686_gyro_reg_to_fs(uint8_t fs, struct sensor_value *out) +{ + switch (fs) { + case ICM42686_DT_GYRO_FS_4000: + sensor_degrees_to_rad(4000, out); + return; + case ICM42686_DT_GYRO_FS_2000: + sensor_degrees_to_rad(2000, out); + return; + case ICM42686_DT_GYRO_FS_1000: + sensor_degrees_to_rad(1000, out); + return; + case ICM42686_DT_GYRO_FS_500: + sensor_degrees_to_rad(500, out); + return; + case ICM42686_DT_GYRO_FS_250: + sensor_degrees_to_rad(250, out); + return; + case ICM42686_DT_GYRO_FS_125: + sensor_degrees_to_rad(125, out); + return; + case ICM42686_DT_GYRO_FS_62_5: + sensor_10udegrees_to_rad(6250000, out); + return; + case ICM42686_DT_GYRO_FS_31_25: + sensor_10udegrees_to_rad(3125000, out); + return; + } +} + +static inline void icm42688_gyro_reg_to_fs(uint8_t fs, struct sensor_value *out) +{ + switch (fs) { + case ICM42688_DT_GYRO_FS_2000: + sensor_degrees_to_rad(2000, out); + return; + case ICM42688_DT_GYRO_FS_1000: + sensor_degrees_to_rad(1000, out); + return; + case ICM42688_DT_GYRO_FS_500: + sensor_degrees_to_rad(500, out); + return; + case ICM42688_DT_GYRO_FS_250: + sensor_degrees_to_rad(250, out); + return; + case ICM42688_DT_GYRO_FS_125: + sensor_degrees_to_rad(125, out); + return; + case ICM42688_DT_GYRO_FS_62_5: + sensor_10udegrees_to_rad(6250000, out); + return; + case ICM42688_DT_GYRO_FS_31_25: + sensor_10udegrees_to_rad(3125000, out); + return; + case ICM42688_DT_GYRO_FS_15_625: + sensor_10udegrees_to_rad(1562500, out); + return; + } +} + +static inline uint8_t icm4268x_accel_hz_to_reg(uint16_t hz) +{ + if (hz >= 32000) { + return ICM4268X_DT_ACCEL_ODR_32000; + } else if (hz >= 16000) { + return ICM4268X_DT_ACCEL_ODR_16000; + } else if (hz >= 8000) { + return ICM4268X_DT_ACCEL_ODR_8000; + } else if (hz >= 4000) { + return ICM4268X_DT_ACCEL_ODR_4000; + } else if (hz >= 2000) { + return ICM4268X_DT_ACCEL_ODR_2000; + } else if (hz >= 1000) { + return ICM4268X_DT_ACCEL_ODR_1000; + } else if (hz >= 500) { + return ICM4268X_DT_ACCEL_ODR_500; + } else if (hz >= 200) { + return ICM4268X_DT_ACCEL_ODR_200; + } else if (hz >= 100) { + return ICM4268X_DT_ACCEL_ODR_100; + } else if (hz >= 50) { + return ICM4268X_DT_ACCEL_ODR_50; + } else if (hz >= 25) { + return ICM4268X_DT_ACCEL_ODR_25; + } else if (hz >= 12) { + return ICM4268X_DT_ACCEL_ODR_12_5; + } else if (hz >= 6) { + return ICM4268X_DT_ACCEL_ODR_6_25; + } else if (hz >= 3) { + return ICM4268X_DT_ACCEL_ODR_3_125; + } else { + return ICM4268X_DT_ACCEL_ODR_1_5625; + } +} + +static inline void icm4268x_accel_reg_to_hz(uint8_t odr, struct sensor_value *out) +{ + switch (odr) { + case ICM4268X_DT_ACCEL_ODR_32000: + out->val1 = 32000; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_16000: + out->val1 = 1600; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_8000: + out->val1 = 8000; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_4000: + out->val1 = 4000; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_2000: + out->val1 = 2000; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_1000: + out->val1 = 1000; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_500: + out->val1 = 500; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_200: + out->val1 = 200; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_100: + out->val1 = 100; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_50: + out->val1 = 50; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_25: + out->val1 = 25; + out->val2 = 0; + return; + case ICM4268X_DT_ACCEL_ODR_12_5: + out->val1 = 12; + out->val2 = 500000; + return; + case ICM4268X_DT_ACCEL_ODR_6_25: + out->val1 = 6; + out->val2 = 250000; + return; + case ICM4268X_DT_ACCEL_ODR_3_125: + out->val1 = 3; + out->val2 = 125000; + return; + case ICM4268X_DT_ACCEL_ODR_1_5625: + out->val1 = 1; + out->val2 = 562500; + return; + } +} + +static inline uint8_t icm4268x_gyro_odr_to_reg(uint16_t hz) +{ + if (hz >= 32000) { + return ICM4268X_DT_GYRO_ODR_32000; + } else if (hz >= 16000) { + return ICM4268X_DT_GYRO_ODR_16000; + } else if (hz >= 8000) { + return ICM4268X_DT_GYRO_ODR_8000; + } else if (hz >= 4000) { + return ICM4268X_DT_GYRO_ODR_4000; + } else if (hz >= 2000) { + return ICM4268X_DT_GYRO_ODR_2000; + } else if (hz >= 1000) { + return ICM4268X_DT_GYRO_ODR_1000; + } else if (hz >= 500) { + return ICM4268X_DT_GYRO_ODR_500; + } else if (hz >= 200) { + return ICM4268X_DT_GYRO_ODR_200; + } else if (hz >= 100) { + return ICM4268X_DT_GYRO_ODR_100; + } else if (hz >= 50) { + return ICM4268X_DT_GYRO_ODR_50; + } else if (hz >= 25) { + return ICM4268X_DT_GYRO_ODR_25; + } else { + return ICM4268X_DT_GYRO_ODR_12_5; + } +} + +static inline void icm4268x_gyro_reg_to_odr(uint8_t odr, struct sensor_value *out) +{ + switch (odr) { + case ICM4268X_DT_GYRO_ODR_32000: + out->val1 = 32000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_16000: + out->val1 = 16000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_8000: + out->val1 = 8000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_4000: + out->val1 = 4000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_2000: + out->val1 = 2000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_1000: + out->val1 = 1000; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_500: + out->val1 = 500; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_200: + out->val1 = 200; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_100: + out->val1 = 100; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_50: + out->val1 = 50; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_25: + out->val1 = 25; + out->val2 = 0; + return; + case ICM4268X_DT_GYRO_ODR_12_5: + out->val1 = 12; + out->val2 = 500000; + return; + } +} + +/** + * @brief All sensor configuration options + */ +struct icm4268x_aaf_cfg { + uint8_t aaf_delt; + uint16_t aaf_deltsqr; + uint8_t aaf_bitshift; +}; + +struct icm4268x_cfg { + uint16_t dev_id; + uint8_t accel_pwr_mode; + uint8_t accel_fs; + uint8_t accel_odr; + /* TODO accel signal processing options */ + + uint8_t gyro_pwr_mode; + uint8_t gyro_fs; + uint8_t gyro_odr; + /* TODO gyro signal processing options */ + + /* AAF cfg for accel and gyro */ + struct icm4268x_aaf_cfg aaf_cfg[AAF_SENSORS_NUM]; + + bool temp_dis; + /* TODO temp signal processing options */ + + /* TODO timestamp options */ + bool tmst_dis; + bool tmst_fsync_en; + bool tmst_delta_en; + bool tmst_res; + bool tmst_regs_en; + + bool fifo_en; + uint8_t fifo_mode; + uint8_t fifo_ths_int_clr; + uint8_t fifo_full_int_clr; + int32_t batch_ticks; + bool fifo_hires; + /* TODO additional FIFO options */ + + /* TODO interrupt options */ + bool int1_mode; + bool int1_pol; + bool interrupt1_drdy; + bool interrupt1_fifo_ths; + bool interrupt1_fifo_full; +}; + +struct icm4268x_trigger_entry { + struct sensor_trigger trigger; + sensor_trigger_handler_t handler; +}; + +/** + * @brief Device data (struct device) + */ +struct icm4268x_dev_data { + struct icm4268x_cfg cfg; +#ifdef CONFIG_ICM4268X_TRIGGER +#if defined(CONFIG_ICM4268X_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ICM4268X_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#ifdef CONFIG_ICM4268X_STREAM + struct rtio_iodev_sqe *streaming_sqe; + struct rtio *r; + struct rtio_iodev *spi_iodev; + uint8_t int_status; + uint16_t fifo_count; + uint64_t timestamp; + atomic_t reading_fifo; +#endif /* CONFIG_ICM4268X_STREAM */ + const struct device *dev; + struct gpio_callback gpio_cb; + sensor_trigger_handler_t data_ready_handler; + const struct sensor_trigger *data_ready_trigger; + struct k_mutex mutex; +#endif /* CONFIG_ICM4268X_TRIGGER */ + + int16_t readings[7]; +}; + +/** + * @brief Device config (struct device) + */ +struct icm4268x_dev_cfg { + struct spi_dt_spec spi; + struct gpio_dt_spec gpio_int1; + struct gpio_dt_spec gpio_int2; +}; + +/** + * @brief Reset the sensor + * + * @param dev icm4268x device pointer + * + * @retval 0 success + * @retval -EINVAL Reset status or whoami register returned unexpected value. + */ +int icm4268x_reset(const struct device *dev); + +/** + * @brief (Re)Configure the sensor with the given configuration + * + * @param dev icm4268x device pointer + * @param cfg icm4268x_cfg pointer + * + * @retval 0 success + * @retval -errno Error + */ +int icm4268x_configure(const struct device *dev, struct icm4268x_cfg *cfg); + + +/** + * @brief Safely (re)Configure the sensor with the given configuration + * + * Will rollback to prior configuration if new configuration is invalid + * + * @param dev icm4268x device pointer + * @param cfg icm4268x_cfg pointer + * + * @retval 0 success + * @retval -errno Error + */ +int icm4268x_safely_configure(const struct device *dev, struct icm4268x_cfg *cfg); + +/** + * @brief Reads all channels + * + * Regardless of what is enabled/disabled this reads all data registers + * as the time to read the 14 bytes at 1MHz is going to be 112 us which + * is less time than a SPI transaction takes to setup typically. + * + * @param dev icm4268x device pointer + * @param buf 14 byte buffer to store data values (7 channels, 2 bytes each) + * + * @retval 0 success + * @retval -errno Error + */ +int icm4268x_read_all(const struct device *dev, uint8_t data[14]); + +/** + * @brief Convert icm42686 accelerometer value to useful g values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_g whole G's output in int32_t + * @param out_ug micro (1/1000000) of a G output as uint32_t + */ +static inline void icm42686_accel_g(struct icm4268x_cfg *cfg, int32_t in, int32_t *out_g, + uint32_t *out_ug) +{ + int32_t sensitivity; /* value equivalent for 1g */ + + switch (cfg->accel_fs) { + case ICM42686_DT_ACCEL_FS_2: + sensitivity = 16384; + break; + case ICM42686_DT_ACCEL_FS_4: + sensitivity = 8192; + break; + case ICM42686_DT_ACCEL_FS_8: + sensitivity = 4096; + break; + case ICM42686_DT_ACCEL_FS_16: + sensitivity = 2048; + break; + case ICM42686_DT_ACCEL_FS_32: + sensitivity = 1024; + break; + default: + CODE_UNREACHABLE; + } + + /* Whole g's */ + *out_g = in / sensitivity; + + /* Micro g's */ + *out_ug = ((abs(in) - (abs((*out_g)) * sensitivity)) * 1000000) / sensitivity; +} + +/** + * @brief Convert icm42688 accelerometer value to useful g values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_g whole G's output in int32_t + * @param out_ug micro (1/1000000) of a G output as uint32_t + */ +static inline void icm42688_accel_g(struct icm4268x_cfg *cfg, int32_t in, int32_t *out_g, + uint32_t *out_ug) +{ + int32_t sensitivity; /* value equivalent for 1g */ + + switch (cfg->accel_fs) { + case ICM42688_DT_ACCEL_FS_2: + sensitivity = 16384; + break; + case ICM42688_DT_ACCEL_FS_4: + sensitivity = 8192; + break; + case ICM42688_DT_ACCEL_FS_8: + sensitivity = 4096; + break; + case ICM42688_DT_ACCEL_FS_16: + sensitivity = 2048; + break; + default: + CODE_UNREACHABLE; + } + + /* Whole g's */ + *out_g = in / sensitivity; + + /* Micro g's */ + *out_ug = ((abs(in) - (abs((*out_g)) * sensitivity)) * 1000000) / sensitivity; +} + +/** + * @brief Convert icm42686 gyroscope value to useful deg/s values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_dps whole deg/s output in int32_t + * @param out_udps micro (1/1000000) deg/s as uint32_t + */ +static inline void icm42686_gyro_dps(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_dps, + uint32_t *out_udps) +{ + int64_t sensitivity; /* value equivalent for 10x gyro reading deg/s */ + + switch (cfg->gyro_fs) { + case ICM42686_DT_GYRO_FS_4000: + sensitivity = 82; + break; + case ICM42686_DT_GYRO_FS_2000: + sensitivity = 164; + break; + case ICM42686_DT_GYRO_FS_1000: + sensitivity = 328; + break; + case ICM42686_DT_GYRO_FS_500: + sensitivity = 655; + break; + case ICM42686_DT_GYRO_FS_250: + sensitivity = 1310; + break; + case ICM42686_DT_GYRO_FS_125: + sensitivity = 2620; + break; + case ICM42686_DT_GYRO_FS_62_5: + sensitivity = 5243; + break; + case ICM42686_DT_GYRO_FS_31_25: + sensitivity = 10486; + break; + default: + CODE_UNREACHABLE; + } + + int32_t in10 = in * 10; + + /* Whole deg/s */ + *out_dps = in10 / sensitivity; + + /* Micro deg/s */ + *out_udps = ((int64_t)(llabs(in10) - (llabs((*out_dps)) * sensitivity)) * 1000000LL) / + sensitivity; +} + +/** + * @brief Convert icm42688 gyroscope value to useful deg/s values + * + * @param cfg icm42688_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_dps whole deg/s output in int32_t + * @param out_udps micro (1/1000000) deg/s as uint32_t + */ +static inline void icm42688_gyro_dps(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_dps, + uint32_t *out_udps) +{ + int64_t sensitivity; /* value equivalent for 10x gyro reading deg/s */ + + switch (cfg->gyro_fs) { + case ICM42688_DT_GYRO_FS_2000: + sensitivity = 164; + break; + case ICM42688_DT_GYRO_FS_1000: + sensitivity = 328; + break; + case ICM42688_DT_GYRO_FS_500: + sensitivity = 655; + break; + case ICM42688_DT_GYRO_FS_250: + sensitivity = 1310; + break; + case ICM42688_DT_GYRO_FS_125: + sensitivity = 2620; + break; + case ICM42688_DT_GYRO_FS_62_5: + sensitivity = 5243; + break; + case ICM42688_DT_GYRO_FS_31_25: + sensitivity = 10486; + break; + case ICM42688_DT_GYRO_FS_15_625: + sensitivity = 20972; + break; + default: + CODE_UNREACHABLE; + } + + int32_t in10 = in * 10; + + /* Whole deg/s */ + *out_dps = in10 / sensitivity; + + /* Micro deg/s */ + *out_udps = ((int64_t)(llabs(in10) - (llabs((*out_dps)) * sensitivity)) * 1000000LL) / + sensitivity; +} + +/** + * @brief Convert icm42686 accelerometer value to useful m/s^2 values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_ms meters/s^2 (whole) output in int32_t + * @param out_ums micrometers/s^2 output as uint32_t + */ +static inline void icm42686_accel_ms(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_ms, + int32_t *out_ums) +{ + int64_t sensitivity = 0; /* value equivalent for 1g */ + + switch (cfg->accel_fs) { + case ICM42686_DT_ACCEL_FS_2: + sensitivity = 16384; + break; + case ICM42686_DT_ACCEL_FS_4: + sensitivity = 8192; + break; + case ICM42686_DT_ACCEL_FS_8: + sensitivity = 4096; + break; + case ICM42686_DT_ACCEL_FS_16: + sensitivity = 2048; + break; + case ICM42686_DT_ACCEL_FS_32: + sensitivity = 1024; + break; + } + + /* Convert to micrometers/s^2 */ + int64_t in_ms = in * SENSOR_G; + + /* meters/s^2 whole values */ + *out_ms = in_ms / (sensitivity * 1000000LL); + + /* micrometers/s^2 */ + *out_ums = (in_ms - (*out_ms * sensitivity * 1000000LL)) / sensitivity; +} + +/** + * @brief Convert icm42688 accelerometer value to useful m/s^2 values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_ms meters/s^2 (whole) output in int32_t + * @param out_ums micrometers/s^2 output as uint32_t + */ +static inline void icm42688_accel_ms(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_ms, + int32_t *out_ums) +{ + int64_t sensitivity = 0; /* value equivalent for 1g */ + + switch (cfg->accel_fs) { + case ICM42688_DT_ACCEL_FS_2: + sensitivity = 16384; + break; + case ICM42688_DT_ACCEL_FS_4: + sensitivity = 8192; + break; + case ICM42688_DT_ACCEL_FS_8: + sensitivity = 4096; + break; + case ICM42688_DT_ACCEL_FS_16: + sensitivity = 2048; + break; + } + + /* Convert to micrometers/s^2 */ + int64_t in_ms = in * SENSOR_G; + + /* meters/s^2 whole values */ + *out_ms = in_ms / (sensitivity * 1000000LL); + + /* micrometers/s^2 */ + *out_ums = (in_ms - (*out_ms * sensitivity * 1000000LL)) / sensitivity; +} + +/** + * @brief Convert icm42686 gyroscope value to useful rad/s values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_rads whole rad/s output in int32_t + * @param out_urads microrad/s as uint32_t + */ +static inline void icm42686_gyro_rads(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_rads, + int32_t *out_urads) +{ + int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */ + + switch (cfg->gyro_fs) { + case ICM42686_DT_GYRO_FS_4000: + sensitivity = 82; + break; + case ICM42686_DT_GYRO_FS_2000: + sensitivity = 164; + break; + case ICM42686_DT_GYRO_FS_1000: + sensitivity = 328; + break; + case ICM42686_DT_GYRO_FS_500: + sensitivity = 655; + break; + case ICM42686_DT_GYRO_FS_250: + sensitivity = 1310; + break; + case ICM42686_DT_GYRO_FS_125: + sensitivity = 2620; + break; + case ICM42686_DT_GYRO_FS_62_5: + sensitivity = 5243; + break; + case ICM42686_DT_GYRO_FS_31_25: + sensitivity = 10486; + break; + } + + int64_t in10_rads = (int64_t)in * SENSOR_PI * 10LL; + + /* Whole rad/s */ + *out_rads = in10_rads / (sensitivity * 180LL * 1000000LL); + + /* microrad/s */ + *out_urads = + (in10_rads - (*out_rads * sensitivity * 180LL * 1000000LL)) / (sensitivity * 180LL); +} + +/** + * @brief Convert icm42688 gyroscope value to useful rad/s values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_rads whole rad/s output in int32_t + * @param out_urads microrad/s as uint32_t + */ +static inline void icm42688_gyro_rads(const struct icm4268x_cfg *cfg, int32_t in, int32_t *out_rads, + int32_t *out_urads) +{ + int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */ + + switch (cfg->gyro_fs) { + case ICM42688_DT_GYRO_FS_2000: + sensitivity = 164; + break; + case ICM42688_DT_GYRO_FS_1000: + sensitivity = 328; + break; + case ICM42688_DT_GYRO_FS_500: + sensitivity = 655; + break; + case ICM42688_DT_GYRO_FS_250: + sensitivity = 1310; + break; + case ICM42688_DT_GYRO_FS_125: + sensitivity = 2620; + break; + case ICM42688_DT_GYRO_FS_62_5: + sensitivity = 5243; + break; + case ICM42688_DT_GYRO_FS_31_25: + sensitivity = 10486; + break; + case ICM42688_DT_GYRO_FS_15_625: + sensitivity = 20972; + break; + } + + int64_t in10_rads = (int64_t)in * SENSOR_PI * 10LL; + + /* Whole rad/s */ + *out_rads = in10_rads / (sensitivity * 180LL * 1000000LL); + + /* microrad/s */ + *out_urads = + (in10_rads - (*out_rads * sensitivity * 180LL * 1000000LL)) / (sensitivity * 180LL); +} + +/** + * @brief Convert icm4268x temp value to useful celsius values + * + * @param cfg icm4268x_cfg current device configuration + * @param in raw data value in int32_t format + * @param out_c whole celsius output in int32_t + * @param out_uc micro (1/1000000) celsius as uint32_t + */ +static inline void icm4268x_temp_c(int32_t in, int32_t *out_c, uint32_t *out_uc) +{ + int64_t sensitivity = 13248; /* value equivalent for x100 1c */ + + /* Offset by 25 degrees Celsius */ + int64_t in100 = (in * 100) + (25 * sensitivity); + + /* Whole celsius */ + *out_c = in100 / sensitivity; + + /* Micro celsius */ + *out_uc = ((in100 - (*out_c) * sensitivity) * INT64_C(1000000)) / sensitivity; +} + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_H_ */ diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_common.c b/drivers/sensor/tdk/icm4268x/icm4268x_common.c new file mode 100644 index 0000000000000..cf4e985c0569a --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_common.c @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2022 Esco Medical ApS + * Copyright (c) 2020 TDK Invensense + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "icm4268x.h" +#include "icm4268x_reg.h" +#include "icm4268x_spi.h" +#include "icm4268x_trigger.h" + +#include +LOG_MODULE_REGISTER(ICM4268X_LL, CONFIG_SENSOR_LOG_LEVEL); + +static struct icm4268x_aaf_cfg aaf_cfg_tbl[AAF_BW_MAX_IDX] = { + {1, 1, 15}, + {2, 4, 13}, + {3, 9, 12}, + {4, 16, 11}, + {5, 25, 10}, + {6, 36, 10}, + {7, 49, 9}, + {8, 64, 9}, + {9, 81, 9}, + {10, 100, 8}, + {11, 122, 8}, + {12, 144, 8}, + {13, 170, 8}, + {14, 196, 7}, + {15, 224, 7}, + {16, 256, 7}, + {17, 288, 7}, + {18, 324, 7}, + {19, 360, 6}, + {20, 400, 6}, + {21, 440, 6}, + {22, 488, 6}, + {23, 528, 6}, + {24, 576, 6}, + {25, 624, 6}, + {26, 680, 6}, + {27, 736, 5}, + {28, 784, 5}, + {29, 848, 5}, + {30, 896, 5}, + {31, 960, 5}, + {32, 1024, 5}, + {33, 1088, 5}, + {34, 1152, 5}, + {35, 1232, 5}, + {36, 1296, 5}, + {37, 1376, 4}, + {38, 1440, 4}, + {39, 1536, 4}, + {40, 1600, 4}, + {41, 1696, 4}, + {42, 1760, 4}, + {43, 1856, 4}, + {44, 1952, 4}, + {45, 2016, 4}, + {46, 2112, 4}, + {47, 2208, 4}, + {48, 2304, 4}, + {49, 2400, 4}, + {50, 2496, 4}, + {51, 2592, 4}, + {52, 2720, 4}, + {53, 2816, 3}, + {54, 2944, 3}, + {55, 3008, 3}, + {56, 3136, 3}, + {57, 3264, 3}, + {58, 3392, 3}, + {59, 3456, 3}, + {60, 3584, 3}, + {61, 3712, 3}, + {62, 3840, 3}, + {63, 3968, 3} +}; + +int icm4268x_reset(const struct device *dev) +{ + int res; + uint8_t value; + struct icm4268x_dev_data *data = dev->data; + struct icm4268x_cfg cfg = data->cfg; + const struct icm4268x_dev_cfg *dev_cfg = dev->config; + + /* start up time for register read/write after POR is 1ms and supply ramp time is 3ms */ + k_msleep(3); + + /* perform a soft reset to ensure a clean slate, reset bit will auto-clear */ + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_DEVICE_CONFIG, BIT_SOFT_RESET); + + if (res) { + LOG_ERR("write REG_SIGNAL_PATH_RESET failed"); + return res; + } + + /* wait for soft reset to take effect */ + k_msleep(SOFT_RESET_TIME_MS); + + /* clear reset done int flag */ + res = icm4268x_spi_read(&dev_cfg->spi, REG_INT_STATUS, &value, 1); + + if (res) { + return res; + } + + if (FIELD_GET(BIT_INT_STATUS_RESET_DONE, value) != 1) { + LOG_ERR("unexpected RESET_DONE value, %i", value); + return -EINVAL; + } + + res = icm4268x_spi_read(&dev_cfg->spi, REG_WHO_AM_I, &value, 1); + if (res) { + return res; + } + + if (value != cfg.dev_id) { + LOG_ERR("invalid WHO_AM_I value, was %i but expected %i", value, cfg.dev_id); + return -EINVAL; + } + + return 0; +} + +static uint16_t icm4268x_compute_fifo_wm(const struct icm4268x_cfg *cfg) +{ + const bool accel_enabled = cfg->accel_pwr_mode != ICM4268X_DT_ACCEL_OFF; + const bool gyro_enabled = cfg->gyro_pwr_mode != ICM4268X_DT_GYRO_OFF; + const int pkt_size = cfg->fifo_hires ? 20 : (accel_enabled && gyro_enabled ? 16 : 8); + int accel_modr = 0; + int gyro_modr = 0; + int64_t modr; + + if (cfg->batch_ticks == 0 || (!accel_enabled && !gyro_enabled)) { + return 0; + } + + if (accel_enabled) { + struct sensor_value val = {0}; + + icm4268x_accel_reg_to_hz(cfg->accel_odr, &val); + accel_modr = sensor_value_to_micro(&val) / 1000; + } + if (gyro_enabled) { + struct sensor_value val = {0}; + + icm4268x_gyro_reg_to_odr(cfg->gyro_odr, &val); + gyro_modr = sensor_value_to_micro(&val) / 1000; + } + + if (accel_modr == 0) { + modr = gyro_modr; + } else if (gyro_modr == 0) { + modr = accel_modr; + } else { + /* Need to find the least common multiplier (LCM) */ + int n1 = accel_modr; + int n2 = gyro_modr; + + while (n1 != n2) { + if (n1 > n2) { + n1 -= n2; + } else { + n2 -= n1; + } + } + LOG_DBG("GCD=%d", n1); + modr = ((int64_t)accel_modr * (int64_t)gyro_modr) / n1; + } + /* At this point we have 'modr' as mHz which is 1 / msec. */ + + /* Convert 'modr' to bytes * batch_ticks / msec */ + modr *= (int64_t)cfg->batch_ticks * pkt_size; + + /* 'modr' = byte_ticks_per_msec / kticks_per_sec */ + modr = DIV_ROUND_UP(modr, CONFIG_SYS_CLOCK_TICKS_PER_SEC * INT64_C(1000)); + + return (uint16_t)MIN(modr, 0x7ff); +} + +int icm4268x_configure(const struct device *dev, struct icm4268x_cfg *cfg) +{ + struct icm4268x_dev_data *dev_data = dev->data; + const struct icm4268x_dev_cfg *dev_cfg = dev->config; + int res; + + /* Disable interrupts, reconfigured at end */ + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, 0); + + /* if fifo is enabled right now, disable and flush */ + if (dev_data->cfg.fifo_en) { + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, + FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_BYPASS)); + + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG"); + return -EINVAL; + } + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_SIGNAL_PATH_RESET, + FIELD_PREP(BIT_FIFO_FLUSH, 1)); + + if (res != 0) { + LOG_ERR("Error flushing fifo"); + return -EINVAL; + } + } + + /* TODO maybe do the next few steps intelligently by checking current config */ + /* Power management to set gyro/accel modes */ + uint8_t pwr_mgmt0 = FIELD_PREP(MASK_GYRO_MODE, cfg->gyro_pwr_mode) | + FIELD_PREP(MASK_ACCEL_MODE, cfg->accel_pwr_mode) | + FIELD_PREP(BIT_TEMP_DIS, cfg->temp_dis); + + LOG_DBG("PWR_MGMT0 (0x%x) 0x%x", REG_PWR_MGMT0, pwr_mgmt0); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_PWR_MGMT0, pwr_mgmt0); + + if (res != 0) { + LOG_ERR("Error writing PWR_MGMT0"); + return -EINVAL; + } + + /* Need to wait at least 200us before updating more registers + * see datasheet 14.36 + */ + k_busy_wait(250); + + uint8_t accel_config0 = FIELD_PREP(MASK_ACCEL_ODR, cfg->accel_odr) | + FIELD_PREP(MASK_ACCEL_UI_FS_SEL, cfg->accel_fs); + + LOG_DBG("ACCEL_CONFIG0 (0x%x) 0x%x", REG_ACCEL_CONFIG0, accel_config0); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_ACCEL_CONFIG0, accel_config0); + if (res != 0) { + LOG_ERR("Error writing ACCEL_CONFIG0"); + return -EINVAL; + } + + uint8_t gyro_config0 = FIELD_PREP(MASK_GYRO_ODR, cfg->gyro_odr) | + FIELD_PREP(MASK_GYRO_UI_FS_SEL, cfg->gyro_fs); + + LOG_DBG("GYRO_CONFIG0 (0x%x) 0x%x", REG_GYRO_CONFIG0, gyro_config0); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_GYRO_CONFIG0, gyro_config0); + if (res != 0) { + LOG_ERR("Error writing GYRO_CONFIG0"); + return -EINVAL; + } + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_GYRO_CONFIG1, 0); + if (res != 0) { + LOG_ERR("Error writing GYRO_CONFIG1"); + return -EINVAL; + } + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_GYRO_ACCEL_CONFIG0, 0); + if (res != 0) { + LOG_ERR("Error writing GYRO_ACCEL_CONFIG0"); + return -EINVAL; + } + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_ACCEL_CONFIG1, 0); + if (res != 0) { + LOG_ERR("Error writing ACCEL_CONFIG1"); + return -EINVAL; + } + + /* Accelerometer AAF Configuration */ + uint8_t aaf_tbl_idx = ((cfg->aaf_cfg[AAF_ACCEL_IDX].aaf_delt) - 1); + + uint8_t aaf_cfg_static2 = + ((cfg->aaf_cfg[AAF_ACCEL_IDX].aaf_delt << 1) & MASK_ACCEL_AAF_DELT); + + LOG_DBG("ACCEL_CONFIG_STATIC2 (0x%x) 0x%x", ACCEL_CONFIG_STATIC2, aaf_cfg_static2); + res = icm4268x_spi_single_write(&dev_cfg->spi, ACCEL_CONFIG_STATIC2, aaf_cfg_static2); + if (res != 0) { + LOG_ERR("Error writing ACCEL_CONFIG_STATIC2"); + return -EINVAL; + } + + uint8_t aaf_deltsqr_lsb = + (aaf_cfg_tbl[aaf_tbl_idx].aaf_deltsqr) & MASK_ACCEL_AAF_DELTSQR_LSB; + + LOG_DBG("ACCEL_CONFIG_STATIC3 (0x%x) 0x%x", ACCEL_CONFIG_STATIC3, aaf_deltsqr_lsb); + res = icm4268x_spi_single_write(&dev_cfg->spi, ACCEL_CONFIG_STATIC3, aaf_deltsqr_lsb); + if (res != 0) { + LOG_ERR("Error writing ACCEL_CONFIG_STATIC3"); + return -EINVAL; + } + + uint8_t aaf_deltsqr_msb = + ((aaf_cfg_tbl[aaf_tbl_idx].aaf_deltsqr) >> 0x8) & MASK_ACCEL_AAF_DELTSQR_MSB; + uint8_t aaf_bitshift = + ((aaf_cfg_tbl[aaf_tbl_idx].aaf_bitshift) << 0x4) & MASK_ACCEL_AAF_BITSHIFT; + uint8_t aaf_cfg_static4 = (aaf_bitshift | aaf_deltsqr_msb); + + LOG_DBG("ACCEL_CONFIG_STATIC4 (0x%x) 0x%x", ACCEL_CONFIG_STATIC4, aaf_cfg_static4); + res = icm4268x_spi_single_write(&dev_cfg->spi, ACCEL_CONFIG_STATIC4, aaf_cfg_static4); + if (res != 0) { + LOG_ERR("Error writing ACCEL_CONFIG_STATIC4"); + return -EINVAL; + } + + /* Gyroscope AAF Configuration */ + aaf_tbl_idx = ((cfg->aaf_cfg[AAF_GYRO_IDX].aaf_delt) - 1); + + uint8_t aaf_cfg_static3 = ((cfg->aaf_cfg[AAF_GYRO_IDX].aaf_delt << 1) & MASK_GYRO_AAF_DELT); + + LOG_DBG("GYRO_CONFIG_STATIC3 (0x%x) 0x%x", GYRO_CONFIG_STATIC3, aaf_cfg_static3); + res = icm4268x_spi_single_write(&dev_cfg->spi, GYRO_CONFIG_STATIC3, aaf_cfg_static3); + if (res != 0) { + LOG_ERR("Error writing GYRO_CONFIG_STATIC3"); + return -EINVAL; + } + + aaf_deltsqr_lsb = (aaf_cfg_tbl[aaf_tbl_idx].aaf_deltsqr) & MASK_GYRO_AAF_DELTSQR_LSB; + + LOG_DBG("GYRO_CONFIG_STATIC4 (0x%x) 0x%x", GYRO_CONFIG_STATIC4, aaf_deltsqr_lsb); + res = icm4268x_spi_single_write(&dev_cfg->spi, GYRO_CONFIG_STATIC4, aaf_deltsqr_lsb); + if (res != 0) { + LOG_ERR("Error writing GYRO_CONFIG_STATIC4"); + return -EINVAL; + } + + aaf_deltsqr_msb = + ((aaf_cfg_tbl[aaf_tbl_idx].aaf_deltsqr) >> 0x8) & MASK_GYRO_AAF_DELTSQR_MSB; + aaf_bitshift = ((aaf_cfg_tbl[aaf_tbl_idx].aaf_bitshift) << 0x4) & MASK_GYRO_AAF_BITSHIFT; + uint8_t aaf_cfg_static5 = (aaf_bitshift | aaf_deltsqr_msb); + + LOG_DBG("GYRO_CONFIG_STATIC5 (0x%x) 0x%x", GYRO_CONFIG_STATIC5, aaf_cfg_static5); + res = icm4268x_spi_single_write(&dev_cfg->spi, GYRO_CONFIG_STATIC5, aaf_cfg_static5); + if (res != 0) { + LOG_ERR("Error writing GYRO_CONFIG_STATIC5"); + return -EINVAL; + } + + /* + * Accelerometer sensor need at least 10ms startup time + * Gyroscope sensor need at least 30ms startup time + */ + k_msleep(50); + + /* Ensure FIFO is in bypass mode */ + uint8_t fifo_config_bypass = FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_BYPASS); + + LOG_DBG("FIFO_CONFIG (0x%x) 0x%x", REG_FIFO_CONFIG, fifo_config_bypass); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, fifo_config_bypass); + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG"); + return -EINVAL; + } + + /* Disable FSYNC */ + uint8_t tmst_config; + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FSYNC_CONFIG, 0); + if (res != 0) { + LOG_ERR("Error writing FSYNC_CONFIG"); + return -EINVAL; + } + res = icm4268x_spi_read(&dev_cfg->spi, REG_TMST_CONFIG, &tmst_config, 1); + if (res != 0) { + LOG_ERR("Error reading TMST_CONFIG"); + return -EINVAL; + } + + tmst_config |= (cfg->tmst_dis ? 0 : BIT_TMST_EN); + tmst_config |= (cfg->tmst_fsync_en ? BIT_TMST_FSYNC_EN : 0); + tmst_config |= (cfg->tmst_delta_en ? BIT_TMST_DELTA_EN : 0); + tmst_config |= (cfg->tmst_res ? BIT_TMST_RES : 0); + tmst_config |= (cfg->tmst_regs_en ? BIT_TMST_TO_REGS_EN : 0); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_TMST_CONFIG, tmst_config & ~BIT(1)); + if (res != 0) { + LOG_ERR("Error writing TMST_CONFIG"); + return -EINVAL; + } + + /* Interface Configuration */ + uint8_t intf_config0 = FIELD_PREP(MASK_UI_SIFS_CFG, BIT_UI_SIFS_CFG_DISABLE_I2C) + | BIT_SENSOR_DATA_ENDIAN | BIT_FIFO_COUNT_ENDIAN; + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG0, intf_config0); + if (res != 0) { + LOG_ERR("Error writing INTF_CONFIG0"); + return -EINVAL; + } + + uint8_t intf_config1; + + res = icm4268x_spi_read(&dev_cfg->spi, REG_INTF_CONFIG1, &intf_config1, 1); + if (res != 0) { + LOG_ERR("Error reading INTF_CONFIG1"); + return -EINVAL; + } + + /* Disable Adaptive Full Scale Range Mode */ + intf_config1 = BIT_AFSR_SET | (intf_config1 & 0x1F); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG1, intf_config1); + if (res != 0) { + LOG_ERR("Error writing INTF_CONFIG1"); + return -EINVAL; + } + + /* Select the interrupt mode */ + if (IS_ENABLED(CONFIG_ICM4268X_TRIGGER)) { + res = icm4268x_trigger_enable_interrupt(dev, cfg); + } else { + uint8_t int1_pol = (cfg->int1_pol ? BIT_INT1_POLARITY:0); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, + BIT_INT1_DRIVE_CIRCUIT | int1_pol + | (cfg->int1_mode ? BIT_INT1_MODE : 0)); + } + + if (res) { + LOG_ERR("Error writing to INT_CONFIG"); + return res; + } + + uint8_t int_config1 = 0; + + if ((cfg->accel_odr <= ICM4268X_DT_ACCEL_ODR_4000 || + cfg->gyro_odr <= ICM4268X_DT_GYRO_ODR_4000)) { + int_config1 = FIELD_PREP(BIT_INT_TPULSE_DURATION, 1) | + FIELD_PREP(BIT_INT_TDEASSERT_DISABLE, 1); + } + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG1, int_config1); + if (res) { + LOG_ERR("Error writing to INT_CONFIG1"); + return res; + } + + /* fifo configuration steps if desired */ + if (cfg->fifo_en) { + LOG_INF("FIFO ENABLED"); + + /* Setup desired FIFO packet fields based on the other + * temp/accel/gyro en fields in cfg + */ + /* FSYNC is not used in this driver so as per 14.45 its is not + * mandatory to set it to 1. + */ + /* Enabling watermark interrupt based on REG_INT_SOURCE0 + * Enabling High Resolution for better accuracy + */ + uint8_t fifo_cfg1 = + FIELD_PREP(BIT_FIFO_TEMP_EN, 1) | FIELD_PREP(BIT_FIFO_GYRO_EN, 1) | + FIELD_PREP(BIT_FIFO_ACCEL_EN, 1) | FIELD_PREP(BIT_FIFO_HIRES_EN, 1) | + FIELD_PREP(BIT_FIFO_WM_GT_TH, 1); + + LOG_DBG("FIFO_CONFIG1 (0x%x) 0x%x", REG_FIFO_CONFIG1, fifo_cfg1); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG1, fifo_cfg1); + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG1"); + return -EINVAL; + } + + /* Set watermark and interrupt handling first */ + uint16_t fifo_wm = icm4268x_compute_fifo_wm(cfg); + uint8_t fifo_wml = fifo_wm & 0xFF; + + LOG_DBG("FIFO_CONFIG2( (0x%x)) (WM Low) 0x%x", REG_FIFO_CONFIG2, fifo_wml); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG2, fifo_wml); + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG2"); + return -EINVAL; + } + + uint8_t fifo_wmh = (fifo_wm >> 8) & 0x0F; + + LOG_DBG("FIFO_CONFIG3 (0x%x) (WM High) 0x%x", REG_FIFO_CONFIG3, fifo_wmh); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG3, fifo_wmh); + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG3"); + return -EINVAL; + } + + /* Begin streaming */ + uint8_t fifo_config = FIELD_PREP(MASK_FIFO_MODE, cfg->fifo_mode); + + LOG_DBG("FIFO_CONFIG (0x%x) 0x%x", REG_FIFO_CONFIG, fifo_config); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG, fifo_config); + + if (res != 0) { + LOG_ERR("Error writing FIFO_CONFIG"); + return -EINVAL; + } + + /* Select the condition to clear the interrupt line in latched mode */ + if (cfg->int1_mode == ICM4268X_DT_INT1_MODE_LATCHED) { + uint8_t int_config0; + + int_config0 = FIELD_PREP(MASK_FIFO_FULL_INT_CLR, cfg->fifo_full_int_clr) + | FIELD_PREP(MASK_FIFO_THS_INT_CLEAR, cfg->fifo_ths_int_clr); + + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG0, + int_config0); + if (res != 0) { + LOG_ERR("Error writing INT_CONFIG0"); + return -EINVAL; + } + } + /* Config interrupt source to only be fifo wm/full */ + uint8_t int_source0 = BIT_FIFO_FULL_INT1_EN | BIT_FIFO_THS_INT1_EN; + + LOG_DBG("INT_SOURCE0 (0x%x) 0x%x", REG_INT_SOURCE0, int_source0); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, int_source0); + if (res) { + return res; + } + } else { + LOG_INF("FIFO DISABLED"); + + /* No fifo mode so set data ready as interrupt source */ + uint8_t int_source0 = BIT_UI_DRDY_INT1_EN; + + LOG_DBG("INT_SOURCE0 (0x%x) 0x%x", REG_INT_SOURCE0, int_source0); + res = icm4268x_spi_single_write(&dev_cfg->spi, REG_INT_SOURCE0, int_source0); + if (res) { + return res; + } + } + + return res; +} + +int icm4268x_safely_configure(const struct device *dev, struct icm4268x_cfg *cfg) +{ + struct icm4268x_dev_data *drv_data = dev->data; + int ret = icm4268x_configure(dev, cfg); + + if (ret == 0) { + drv_data->cfg = *cfg; + } else { + ret = icm4268x_configure(dev, &drv_data->cfg); + } + + return ret; +} + +int icm4268x_read_all(const struct device *dev, uint8_t data[14]) +{ + const struct icm4268x_dev_cfg *dev_cfg = dev->config; + int res; + + res = icm4268x_spi_read(&dev_cfg->spi, REG_TEMP_DATA1, data, 14); + + return res; +} diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_decoder.c b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.c new file mode 100644 index 0000000000000..1ff15bedd3762 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.c @@ -0,0 +1,1158 @@ +/* + * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "icm4268x_decoder.h" +#include "icm4268x_reg.h" +#include "icm4268x.h" +#include + +#include +LOG_MODULE_REGISTER(ICM4268X_DECODER, CONFIG_SENSOR_LOG_LEVEL); + +#define DT_DRV_COMPAT invensense_icm4268x + +static int icm42686_get_shift(enum sensor_channel channel, int accel_fs, int gyro_fs, int8_t *shift) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (accel_fs) { + case ICM42686_DT_ACCEL_FS_2: + *shift = 5; + return 0; + case ICM42686_DT_ACCEL_FS_4: + *shift = 6; + return 0; + case ICM42686_DT_ACCEL_FS_8: + *shift = 7; + return 0; + case ICM42686_DT_ACCEL_FS_16: + *shift = 8; + return 0; + case ICM42686_DT_ACCEL_FS_32: + *shift = 9; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (gyro_fs) { + case ICM42686_DT_GYRO_FS_31_25: + *shift = 0; + return 0; + case ICM42686_DT_GYRO_FS_62_5: + *shift = 1; + return 0; + case ICM42686_DT_GYRO_FS_125: + *shift = 2; + return 0; + case ICM42686_DT_GYRO_FS_250: + *shift = 3; + return 0; + case ICM42686_DT_GYRO_FS_500: + *shift = 4; + return 0; + case ICM42686_DT_GYRO_FS_1000: + *shift = 5; + return 0; + case ICM42686_DT_GYRO_FS_2000: + *shift = 6; + return 0; + case ICM42686_DT_GYRO_FS_4000: + *shift = 7; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_DIE_TEMP: + *shift = 9; + return 0; + default: + return -EINVAL; + } +} + +static int icm42688_get_shift(enum sensor_channel channel, int accel_fs, int gyro_fs, int8_t *shift) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (accel_fs) { + case ICM42688_DT_ACCEL_FS_2: + *shift = 5; + return 0; + case ICM42688_DT_ACCEL_FS_4: + *shift = 6; + return 0; + case ICM42688_DT_ACCEL_FS_8: + *shift = 7; + return 0; + case ICM42688_DT_ACCEL_FS_16: + *shift = 8; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (gyro_fs) { + case ICM42688_DT_GYRO_FS_15_625: + *shift = -1; + return 0; + case ICM42688_DT_GYRO_FS_31_25: + *shift = 0; + return 0; + case ICM42688_DT_GYRO_FS_62_5: + *shift = 1; + return 0; + case ICM42688_DT_GYRO_FS_125: + *shift = 2; + return 0; + case ICM42688_DT_GYRO_FS_250: + *shift = 3; + return 0; + case ICM42688_DT_GYRO_FS_500: + *shift = 4; + return 0; + case ICM42688_DT_GYRO_FS_1000: + *shift = 5; + return 0; + case ICM42688_DT_GYRO_FS_2000: + *shift = 6; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_DIE_TEMP: + *shift = 9; + return 0; + default: + return -EINVAL; + } +} + +int icm42686_convert_raw_to_q31(struct icm4268x_cfg *cfg, enum sensor_channel chan, int32_t reading, + q31_t *out) +{ + int32_t whole; + int32_t fraction; + int64_t intermediate; + int8_t shift; + int rc; + + rc = icm42686_get_shift(chan, cfg->accel_fs, cfg->gyro_fs, &shift); + if (rc != 0) { + return rc; + } + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42686_accel_ms(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42686_gyro_rads(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_DIE_TEMP: + icm4268x_temp_c(reading, &whole, &fraction); + break; + default: + return -ENOTSUP; + } + intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); + if (shift < 0) { + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) * (1 << -shift) / INT64_C(1000000); + } else if (shift > 0) { + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) / ((1 << shift) * INT64_C(1000000)); + } + *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); + + return 0; +} + +int icm42688_convert_raw_to_q31(struct icm4268x_cfg *cfg, enum sensor_channel chan, int32_t reading, + q31_t *out) +{ + int32_t whole; + int32_t fraction; + int64_t intermediate; + int8_t shift; + int rc; + + rc = icm42688_get_shift(chan, cfg->accel_fs, cfg->gyro_fs, &shift); + if (rc != 0) { + return rc; + } + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42688_accel_ms(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42688_gyro_rads(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_DIE_TEMP: + icm4268x_temp_c(reading, &whole, &fraction); + break; + default: + return -ENOTSUP; + } + intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); + if (shift < 0) { + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) * (1 << -shift) / INT64_C(1000000); + } else if (shift > 0) { + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) / ((1 << shift) * INT64_C(1000000)); + } + *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); + + return 0; +} + +static int icm4268x_get_channel_position(enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: + return 0; + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + return 1; + case SENSOR_CHAN_ACCEL_Y: + return 2; + case SENSOR_CHAN_ACCEL_Z: + return 3; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + return 4; + case SENSOR_CHAN_GYRO_Y: + return 5; + case SENSOR_CHAN_GYRO_Z: + return 6; + default: + return 0; + } +} + +static uint8_t icm4268x_encode_channel(enum sensor_channel chan) +{ + uint8_t encode_bmask = 0; + + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + encode_bmask = BIT(icm4268x_get_channel_position(chan)); + break; + case SENSOR_CHAN_ACCEL_XYZ: + encode_bmask = BIT(icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_X)) | + BIT(icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Y)) | + BIT(icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Z)); + break; + case SENSOR_CHAN_GYRO_XYZ: + encode_bmask = BIT(icm4268x_get_channel_position(SENSOR_CHAN_GYRO_X)) | + BIT(icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Y)) | + BIT(icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Z)); + break; + default: + break; + } + + return encode_bmask; +} + +int icm4268x_encode(const struct device *dev, const struct sensor_chan_spec *const channels, + const size_t num_channels, uint8_t *buf) +{ + struct icm4268x_dev_data *data = dev->data; + struct icm4268x_encoded_data *edata = (struct icm4268x_encoded_data *)buf; + + edata->channels = 0; + + for (int i = 0; i < num_channels; i++) { + edata->channels |= icm4268x_encode_channel(channels[i].chan_type); + } + + edata->header.is_fifo = false; + edata->header.accel_fs = data->cfg.accel_fs; + edata->header.gyro_fs = data->cfg.gyro_fs; + edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + return 0; +} + +#define IS_ACCEL(chan) ((chan) >= SENSOR_CHAN_ACCEL_X && (chan) <= SENSOR_CHAN_ACCEL_XYZ) +#define IS_GYRO(chan) ((chan) >= SENSOR_CHAN_GYRO_X && (chan) <= SENSOR_CHAN_GYRO_XYZ) + +static inline q31_t icm4268x_read_temperature_from_packet(const uint8_t *pkt) +{ + int32_t temperature; + int32_t whole; + int32_t fraction; + + /* Temperature always assumes a shift of 9 for a range of (-273,273) C */ + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + temperature = (pkt[0xd] << 8) | pkt[0xe]; + + icm4268x_temp_c(temperature, &whole, &fraction); + } else { + if (FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1 && + FIELD_GET(FIFO_HEADER_GYRO, pkt[0]) == 1) { + temperature = pkt[0xd]; + } else { + temperature = pkt[0x7]; + } + + int64_t sensitivity = 207; + int64_t temperature100 = (temperature * 100) + (25 * sensitivity); + + whole = temperature100 / sensitivity; + fraction = + ((temperature100 - whole * sensitivity) * INT64_C(1000000)) / sensitivity; + } + __ASSERT_NO_MSG(whole >= -512 && whole <= 511); + return FIELD_PREP(GENMASK(31, 22), whole) | (fraction * GENMASK64(21, 0) / 1000000); +} + +static int icm42686_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs, + uint8_t axis_offset, q31_t *out) +{ + int32_t value; + int64_t scale = 0; + int32_t max = BIT(15); + int offset = 1 + (axis_offset * 2); + + if (is_accel) { + switch (fs) { + case ICM42686_DT_ACCEL_FS_2: + scale = INT64_C(2) * BIT(31 - 5) * 9.80665; + break; + case ICM42686_DT_ACCEL_FS_4: + scale = INT64_C(4) * BIT(31 - 6) * 9.80665; + break; + case ICM42686_DT_ACCEL_FS_8: + scale = INT64_C(8) * BIT(31 - 7) * 9.80665; + break; + case ICM42686_DT_ACCEL_FS_16: + scale = INT64_C(16) * BIT(31 - 8) * 9.80665; + break; + case ICM42686_DT_ACCEL_FS_32: + scale = INT64_C(32) * BIT(31 - 8) * 9.80665; + break; + } + } else { + switch (fs) { + case ICM42686_DT_GYRO_FS_4000: + scale = 82; + break; + case ICM42686_DT_GYRO_FS_2000: + scale = 164; + break; + case ICM42686_DT_GYRO_FS_1000: + scale = 328; + break; + case ICM42686_DT_GYRO_FS_500: + scale = 655; + break; + case ICM42686_DT_GYRO_FS_250: + scale = 1310; + break; + case ICM42686_DT_GYRO_FS_125: + scale = 2620; + break; + case ICM42686_DT_GYRO_FS_62_5: + scale = 5243; + break; + case ICM42686_DT_GYRO_FS_31_25: + scale = 10486; + break; + } + } + + if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) { + offset += 7; + } + + value = (int16_t)sys_le16_to_cpu((pkt[offset] << 8) | pkt[offset + 1]); + + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0); + + offset = 0x11 + axis_offset; + value = (value << 4) | FIELD_GET(mask, pkt[offset]); + /* In 20 bit mode, FS can only be +/-16g and +/-2000dps */ + scale = is_accel ? (INT64_C(16) * BIT(8) * 9.80665) : 131; + max = is_accel ? BIT(18) : BIT(19); + if (value == -524288) { + /* Invalid 20 bit value */ + return -ENODATA; + } + } else { + if (value <= -32767) { + /* Invalid 16 bit value */ + return -ENODATA; + } + } + + *out = (q31_t)(value * scale / max); + return 0; +} +static int icm42688_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs, + uint8_t axis_offset, q31_t *out) +{ + int32_t value; + int64_t scale = 0; + int32_t max = BIT(15); + int offset = 1 + (axis_offset * 2); + + if (is_accel) { + switch (fs) { + case ICM42688_DT_ACCEL_FS_2: + scale = INT64_C(2) * BIT(31 - 5) * 9.80665; + break; + case ICM42688_DT_ACCEL_FS_4: + scale = INT64_C(4) * BIT(31 - 6) * 9.80665; + break; + case ICM42688_DT_ACCEL_FS_8: + scale = INT64_C(8) * BIT(31 - 7) * 9.80665; + break; + case ICM42688_DT_ACCEL_FS_16: + scale = INT64_C(16) * BIT(31 - 8) * 9.80665; + break; + } + } else { + switch (fs) { + case ICM42688_DT_GYRO_FS_2000: + scale = 164; + break; + case ICM42688_DT_GYRO_FS_1000: + scale = 328; + break; + case ICM42688_DT_GYRO_FS_500: + scale = 655; + break; + case ICM42688_DT_GYRO_FS_250: + scale = 1310; + break; + case ICM42688_DT_GYRO_FS_125: + scale = 2620; + break; + case ICM42688_DT_GYRO_FS_62_5: + scale = 5243; + break; + case ICM42688_DT_GYRO_FS_31_25: + scale = 10486; + break; + case ICM42688_DT_GYRO_FS_15_625: + scale = 20972; + break; + } + } + + if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) { + offset += 7; + } + + value = (int16_t)sys_le16_to_cpu((pkt[offset] << 8) | pkt[offset + 1]); + + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0); + + offset = 0x11 + axis_offset; + value = (value << 4) | FIELD_GET(mask, pkt[offset]); + /* In 20 bit mode, FS can only be +/-16g and +/-2000dps */ + scale = is_accel ? (INT64_C(16) * BIT(8) * 9.80665) : 131; + max = is_accel ? BIT(18) : BIT(19); + if (value == -524288) { + /* Invalid 20 bit value */ + return -ENODATA; + } + } else { + if (value <= -32767) { + /* Invalid 16 bit value */ + return -ENODATA; + } + } + + *out = (q31_t)(value * scale / max); + return 0; +} + +static uint32_t accel_period_ns[] = { + [ICM4268X_DT_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625, + [ICM4268X_DT_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250, + [ICM4268X_DT_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500, + [ICM4268X_DT_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM4268X_DT_ACCEL_ODR_25] = UINT32_C(1000000000) / 25, + [ICM4268X_DT_ACCEL_ODR_50] = UINT32_C(1000000000) / 50, + [ICM4268X_DT_ACCEL_ODR_100] = UINT32_C(1000000000) / 100, + [ICM4268X_DT_ACCEL_ODR_200] = UINT32_C(1000000000) / 200, + [ICM4268X_DT_ACCEL_ODR_500] = UINT32_C(1000000000) / 500, + [ICM4268X_DT_ACCEL_ODR_1000] = UINT32_C(1000000), + [ICM4268X_DT_ACCEL_ODR_2000] = UINT32_C(1000000) / 2, + [ICM4268X_DT_ACCEL_ODR_4000] = UINT32_C(1000000) / 4, + [ICM4268X_DT_ACCEL_ODR_8000] = UINT32_C(1000000) / 8, + [ICM4268X_DT_ACCEL_ODR_16000] = UINT32_C(1000000) / 16, + [ICM4268X_DT_ACCEL_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static uint32_t gyro_period_ns[] = { + [ICM4268X_DT_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM4268X_DT_GYRO_ODR_25] = UINT32_C(1000000000) / 25, + [ICM4268X_DT_GYRO_ODR_50] = UINT32_C(1000000000) / 50, + [ICM4268X_DT_GYRO_ODR_100] = UINT32_C(1000000000) / 100, + [ICM4268X_DT_GYRO_ODR_200] = UINT32_C(1000000000) / 200, + [ICM4268X_DT_GYRO_ODR_500] = UINT32_C(1000000000) / 500, + [ICM4268X_DT_GYRO_ODR_1000] = UINT32_C(1000000), + [ICM4268X_DT_GYRO_ODR_2000] = UINT32_C(1000000) / 2, + [ICM4268X_DT_GYRO_ODR_4000] = UINT32_C(1000000) / 4, + [ICM4268X_DT_GYRO_ODR_8000] = UINT32_C(1000000) / 8, + [ICM4268X_DT_GYRO_ODR_16000] = UINT32_C(1000000) / 16, + [ICM4268X_DT_GYRO_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static int icm42686_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_fifo_data *edata = (const struct icm4268x_fifo_data *)buffer; + const uint8_t *buffer_end = buffer + sizeof(struct icm4268x_fifo_data) + edata->fifo_count; + int accel_frame_count = 0; + int gyro_frame_count = 0; + int count = 0; + int rc; + + if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) { + return 0; + } + + ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; + + buffer += sizeof(struct icm4268x_fifo_data); + while (count < max_count && buffer < buffer_end) { + const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1; + const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1; + const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1; + const uint8_t *frame_end = buffer; + + if (is_20b) { + frame_end += 20; + } else if (has_accel && has_gyro) { + frame_end += 16; + } else { + frame_end += 8; + } + if (has_accel) { + accel_frame_count++; + } + if (has_gyro) { + gyro_frame_count++; + } + + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) { + struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; + + data->shift = 9; + if (has_accel) { + data->readings[count].timestamp_delta = + accel_period_ns[edata->accel_odr] * (accel_frame_count - 1); + } else { + data->readings[count].timestamp_delta = + gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1); + } + data->readings[count].temperature = + icm4268x_read_temperature_from_packet(buffer); + } else if (IS_ACCEL(chan_spec.chan_type) && has_accel) { + /* Decode accel */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->accel_odr]; + + icm42686_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns; + rc = icm42686_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0, + &data->readings[count].x); + rc |= icm42686_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1, + &data->readings[count].y); + rc |= icm42686_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2, + &data->readings[count].z); + if (rc != 0) { + accel_frame_count--; + buffer = frame_end; + continue; + } + } else if (IS_GYRO(chan_spec.chan_type) && has_gyro) { + /* Decode gyro */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->gyro_odr]; + + icm42686_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns; + rc = icm42686_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0, + &data->readings[count].x); + rc |= icm42686_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1, + &data->readings[count].y); + rc |= icm42686_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2, + &data->readings[count].z); + if (rc != 0) { + gyro_frame_count--; + buffer = frame_end; + continue; + } + } + buffer = frame_end; + *fit = (uintptr_t)frame_end; + count++; + } + return count; +} + +static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_fifo_data *edata = (const struct icm4268x_fifo_data *)buffer; + const uint8_t *buffer_end = buffer + sizeof(struct icm4268x_fifo_data) + edata->fifo_count; + int accel_frame_count = 0; + int gyro_frame_count = 0; + int count = 0; + int rc; + + if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) { + return 0; + } + + ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; + + buffer += sizeof(struct icm4268x_fifo_data); + while (count < max_count && buffer < buffer_end) { + const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1; + const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1; + const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1; + const uint8_t *frame_end = buffer; + + if (is_20b) { + frame_end += 20; + } else if (has_accel && has_gyro) { + frame_end += 16; + } else { + frame_end += 8; + } + if (has_accel) { + accel_frame_count++; + } + if (has_gyro) { + gyro_frame_count++; + } + + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) { + struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; + + data->shift = 9; + if (has_accel) { + data->readings[count].timestamp_delta = + accel_period_ns[edata->accel_odr] * (accel_frame_count - 1); + } else { + data->readings[count].timestamp_delta = + gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1); + } + data->readings[count].temperature = + icm4268x_read_temperature_from_packet(buffer); + } else if (IS_ACCEL(chan_spec.chan_type) && has_accel) { + /* Decode accel */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->accel_odr]; + + icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2, + &data->readings[count].z); + if (rc != 0) { + accel_frame_count--; + buffer = frame_end; + continue; + } + } else if (IS_GYRO(chan_spec.chan_type) && has_gyro) { + /* Decode gyro */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->gyro_odr]; + + icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2, + &data->readings[count].z); + if (rc != 0) { + gyro_frame_count--; + buffer = frame_end; + continue; + } + } + buffer = frame_end; + *fit = (uintptr_t)frame_end; + count++; + } + return count; +} + +static int icm42686_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_encoded_data *edata = (const struct icm4268x_encoded_data *)buffer; + const struct icm4268x_decoder_header *header = &edata->header; + struct icm4268x_cfg cfg = { + .accel_fs = edata->header.accel_fs, + .gyro_fs = edata->header.gyro_fs, + }; + uint8_t channel_request; + int rc; + + if (*fit != 0) { + return 0; + } + if (max_count == 0 || chan_spec.chan_idx != 0) { + return -EINVAL; + } + + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_ACCEL_XYZ); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = icm42686_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_X, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_X)], + &out->readings[0].x); + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_Y, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Y)], + &out->readings[0].y); + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_Z, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Z)], + &out->readings[0].z); + *fit = 1; + return 1; + } + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_GYRO_XYZ); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = icm42686_get_shift(SENSOR_CHAN_GYRO_XYZ, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + + out->readings[0].timestamp_delta = 0; + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_X, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_X)], + &out->readings[0].x); + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_Y, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Y)], + &out->readings[0].y); + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_Z, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Z)], + &out->readings[0].z); + *fit = 1; + return 1; + } + case SENSOR_CHAN_DIE_TEMP: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_DIE_TEMP); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_q31_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + + rc = icm42686_get_shift(SENSOR_CHAN_DIE_TEMP, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + out->readings[0].timestamp_delta = 0; + icm42686_convert_raw_to_q31( + &cfg, SENSOR_CHAN_DIE_TEMP, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_DIE_TEMP)], + &out->readings[0].temperature); + *fit = 1; + return 1; + } + default: + return -EINVAL; + } +} + +static int icm42688_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_encoded_data *edata = (const struct icm4268x_encoded_data *)buffer; + const struct icm4268x_decoder_header *header = &edata->header; + struct icm4268x_cfg cfg = { + .accel_fs = edata->header.accel_fs, + .gyro_fs = edata->header.gyro_fs, + }; + uint8_t channel_request; + int rc; + + if (*fit != 0) { + return 0; + } + if (max_count == 0 || chan_spec.chan_idx != 0) { + return -EINVAL; + } + + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_ACCEL_XYZ); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_X, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_X)], + &out->readings[0].x); + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_Y, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Y)], + &out->readings[0].y); + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_ACCEL_Z, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_ACCEL_Z)], + &out->readings[0].z); + *fit = 1; + return 1; + } + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_GYRO_XYZ); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + + out->readings[0].timestamp_delta = 0; + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_X, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_X)], + &out->readings[0].x); + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_Y, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Y)], + &out->readings[0].y); + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_GYRO_Z, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_GYRO_Z)], + &out->readings[0].z); + *fit = 1; + return 1; + } + case SENSOR_CHAN_DIE_TEMP: { + channel_request = icm4268x_encode_channel(SENSOR_CHAN_DIE_TEMP); + if ((channel_request & edata->channels) != channel_request) { + return -ENODATA; + } + + struct sensor_q31_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + + rc = icm42688_get_shift(SENSOR_CHAN_DIE_TEMP, header->accel_fs, header->gyro_fs, + &out->shift); + if (rc != 0) { + return -EINVAL; + } + out->readings[0].timestamp_delta = 0; + icm42688_convert_raw_to_q31( + &cfg, SENSOR_CHAN_DIE_TEMP, + edata->readings[icm4268x_get_channel_position(SENSOR_CHAN_DIE_TEMP)], + &out->readings[0].temperature); + *fit = 1; + return 1; + } + default: + return -EINVAL; + } +} + +static int icm42686_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_decoder_header *header = + (const struct icm4268x_decoder_header *)buffer; + + if (header->is_fifo) { + return icm42686_fifo_decode(buffer, chan_spec, fit, max_count, data_out); + } + return icm42686_one_shot_decode(buffer, chan_spec, fit, max_count, data_out); +} + +static int icm42688_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct icm4268x_decoder_header *header = + (const struct icm4268x_decoder_header *)buffer; + + if (header->is_fifo) { + return icm42688_fifo_decode(buffer, chan_spec, fit, max_count, data_out); + } + return icm42688_one_shot_decode(buffer, chan_spec, fit, max_count, data_out); +} + +static int icm4268x_decoder_get_frame_count(const uint8_t *buffer, + struct sensor_chan_spec chan_spec, + uint16_t *frame_count) +{ + const struct icm4268x_fifo_data *data = (const struct icm4268x_fifo_data *)buffer; + const struct icm4268x_decoder_header *header = &data->header; + + if (chan_spec.chan_idx != 0) { + return -ENOTSUP; + } + + if (!header->is_fifo) { + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_DIE_TEMP: + *frame_count = 1; + return 0; + default: + return -ENOTSUP; + } + return 0; + } + + /* Skip the header */ + buffer += sizeof(struct icm4268x_fifo_data); + + uint16_t count = 0; + const uint8_t *end = buffer + data->fifo_count; + + while (buffer < end) { + bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); + int size = is_20b ? 3 : 2; + + if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) { + size += 2; + } + if (is_20b) { + size += 3; + } + + buffer += size; + ++count; + } + + *frame_count = count; + return 0; +} + +static int icm4268x_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, + size_t *frame_size) +{ + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; + case SENSOR_CHAN_DIE_TEMP: + *base_size = sizeof(struct sensor_q31_data); + *frame_size = sizeof(struct sensor_q31_sample_data); + return 0; + default: + return -ENOTSUP; + } +} + +static bool icm2468x_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct icm4268x_fifo_data *edata = (const struct icm4268x_fifo_data *)buffer; + + if (!edata->header.is_fifo) { + return false; + } + + switch (trigger) { + case SENSOR_TRIG_DATA_READY: + return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status); + case SENSOR_TRIG_FIFO_WATERMARK: + return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status); + case SENSOR_TRIG_FIFO_FULL: + return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status); + default: + return false; + } +} + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42686 +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = icm4268x_decoder_get_frame_count, + .get_size_info = icm4268x_decoder_get_size_info, + .decode = icm42686_decoder_decode, + .has_trigger = icm2468x_decoder_has_trigger, +}; + +void icm42686_get_decoder(const struct sensor_decoder_api **decoder) +{ + *decoder = &SENSOR_DECODER_NAME(); +} + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42688 +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = icm4268x_decoder_get_frame_count, + .get_size_info = icm4268x_decoder_get_size_info, + .decode = icm42688_decoder_decode, + .has_trigger = icm2468x_decoder_has_trigger, +}; + +void icm42688_get_decoder(const struct sensor_decoder_api **decoder) +{ + *decoder = &SENSOR_DECODER_NAME(); +} + +int icm4268x_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + struct icm4268x_dev_data *data = dev->data; + struct icm4268x_cfg cfg = data->cfg; + + if (cfg.dev_id == WHO_AM_I_ICM42686) + icm42686_get_decoder(decoder); + else if (cfg.dev_id == WHO_AM_I_ICM42688) + icm42688_get_decoder(decoder); + + return 0; +} diff --git a/drivers/sensor/tdk/icm42688/icm42688_decoder.h b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h similarity index 53% rename from drivers/sensor/tdk/icm42688/icm42688_decoder.h rename to drivers/sensor/tdk/icm4268x/icm4268x_decoder.h index 9eadcbcecad57..84972e0315aeb 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_decoder.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h @@ -1,25 +1,26 @@ /* * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_DECODER_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_DECODER_H_ #include #include -struct icm42688_decoder_header { +struct icm4268x_decoder_header { uint64_t timestamp; uint8_t is_fifo: 1; uint8_t gyro_fs: 3; - uint8_t accel_fs: 2; - uint8_t reserved: 2; + uint8_t accel_fs: 3; + uint8_t reserved: 1; } __attribute__((__packed__)); -struct icm42688_fifo_data { - struct icm42688_decoder_header header; +struct icm4268x_fifo_data { + struct icm4268x_decoder_header header; uint8_t int_status; uint16_t gyro_odr: 4; uint16_t accel_odr: 4; @@ -27,8 +28,8 @@ struct icm42688_fifo_data { uint16_t reserved: 5; } __attribute__((__packed__)); -struct icm42688_encoded_data { - struct icm42688_decoder_header header; +struct icm4268x_encoded_data { + struct icm4268x_decoder_header header; struct { uint8_t channels: 7; uint8_t reserved: 1; @@ -36,9 +37,9 @@ struct icm42688_encoded_data { int16_t readings[7]; }; -int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *const channels, +int icm4268x_encode(const struct device *dev, const struct sensor_chan_spec *const channels, const size_t num_channels, uint8_t *buf); -int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); +int icm4268x_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ */ +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_DECODER_H_ */ diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_emul.c b/drivers/sensor/tdk/icm4268x/icm4268x_emul.c new file mode 100644 index 0000000000000..c04ab2d0c7f3c --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_emul.c @@ -0,0 +1,797 @@ +/* + * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT invensense_icm4268x + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(ICM4268X, CONFIG_SENSOR_LOG_LEVEL); + +#define NUM_REGS (UINT8_MAX >> 1) + +struct icm4268x_emul_data { + uint8_t reg[NUM_REGS]; +}; + +struct icm4268x_emul_cfg { +}; + +void icm4268x_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val, + size_t count) +{ + struct icm4268x_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count < NUM_REGS); + memcpy(data->reg + reg_addr, val, count); +} + +void icm4268x_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val, size_t count) +{ + struct icm4268x_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count < NUM_REGS); + memcpy(val, data->reg + reg_addr, count); +} + +static void icm42686_emul_handle_write(const struct emul *target, uint8_t regn, uint8_t value) +{ + struct icm4268x_emul_data *data = target->data; + + switch (regn) { + case REG_DEVICE_CONFIG: + if (FIELD_GET(BIT_SOFT_RESET, value) == 1) { + /* Perform a soft reset */ + memset(data->reg, 0, NUM_REGS); + /* Initialized the who-am-i register */ + data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42686; + /* Set the bit for the reset being done */ + data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_RESET_DONE; + } + break; + } +} + +static void icm42688_emul_handle_write(const struct emul *target, uint8_t regn, uint8_t value) +{ + struct icm4268x_emul_data *data = target->data; + + switch (regn) { + case REG_DEVICE_CONFIG: + if (FIELD_GET(BIT_SOFT_RESET, value) == 1) { + /* Perform a soft reset */ + memset(data->reg, 0, NUM_REGS); + /* Initialized the who-am-i register */ + data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688; + /* Set the bit for the reset being done */ + data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_RESET_DONE; + } + break; + } +} + +static int icm42686_emul_io_spi(const struct emul *target, const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + struct icm4268x_emul_data *data = target->data; + const struct spi_buf *tx, *rx; + uint8_t regn; + bool is_read; + + ARG_UNUSED(config); + __ASSERT_NO_MSG(tx_bufs != NULL); + + tx = tx_bufs->buffers; + __ASSERT_NO_MSG(tx != NULL); + __ASSERT_NO_MSG(tx->len > 0); + + regn = *(uint8_t *)tx->buf; + is_read = FIELD_GET(REG_SPI_READ_BIT, regn); + regn &= GENMASK(6, 0); + if (is_read) { + __ASSERT_NO_MSG(rx_bufs != NULL); + __ASSERT_NO_MSG(rx_bufs->count > 1); + + rx = &rx_bufs->buffers[1]; + __ASSERT_NO_MSG(rx->buf != NULL); + __ASSERT_NO_MSG(rx->len > 0); + for (uint16_t i = 0; i < rx->len; ++i) { + ((uint8_t *)rx->buf)[i] = data->reg[regn + i]; + } + } else { + /* Writing to regn */ + uint8_t value; + + __ASSERT_NO_MSG(tx_bufs->count > 1); + tx = &tx_bufs->buffers[1]; + + __ASSERT_NO_MSG(tx->len > 0); + value = ((uint8_t *)tx->buf)[0]; + icm42686_emul_handle_write(target, regn, value); + } + + return 0; +} + +static int icm42688_emul_io_spi(const struct emul *target, const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + struct icm4268x_emul_data *data = target->data; + const struct spi_buf *tx, *rx; + uint8_t regn; + bool is_read; + + ARG_UNUSED(config); + __ASSERT_NO_MSG(tx_bufs != NULL); + + tx = tx_bufs->buffers; + __ASSERT_NO_MSG(tx != NULL); + __ASSERT_NO_MSG(tx->len > 0); + + regn = *(uint8_t *)tx->buf; + is_read = FIELD_GET(REG_SPI_READ_BIT, regn); + regn &= GENMASK(6, 0); + if (is_read) { + __ASSERT_NO_MSG(rx_bufs != NULL); + __ASSERT_NO_MSG(rx_bufs->count > 1); + + rx = &rx_bufs->buffers[1]; + __ASSERT_NO_MSG(rx->buf != NULL); + __ASSERT_NO_MSG(rx->len > 0); + for (uint16_t i = 0; i < rx->len; ++i) { + ((uint8_t *)rx->buf)[i] = data->reg[regn + i]; + } + } else { + /* Writing to regn */ + uint8_t value; + + __ASSERT_NO_MSG(tx_bufs->count > 1); + tx = &tx_bufs->buffers[1]; + + __ASSERT_NO_MSG(tx->len > 0); + value = ((uint8_t *)tx->buf)[0]; + icm42688_emul_handle_write(target, regn, value); + } + + return 0; +} + +static int icm42686_emul_init(const struct emul *target, const struct device *parent) +{ + struct icm4268x_emul_data *data = target->data; + + /* Initialized the who-am-i register */ + data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42686; + + return 0; +} + +static int icm42688_emul_init(const struct emul *target, const struct device *parent) +{ + struct icm4268x_emul_data *data = target->data; + + /* Initialized the who-am-i register */ + data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688; + + return 0; +} + +static const struct spi_emul_api icm42686_emul_spi_api = { + .io = icm42686_emul_io_spi, +}; + +static const struct spi_emul_api icm42688_emul_spi_api = { + .io = icm42688_emul_io_spi, +}; + +#define Q31_SCALE ((int64_t)INT32_MAX + 1) + +/** + * @brief Get current full-scale range in g's based on register config, along with corresponding + * sensitivity and shift. See datasheet section 3.2, table 2. + */ +static void icm42686_emul_get_accel_settings(const struct emul *target, int *fs_g, int *sensitivity, + int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_g_out; + int8_t shift_out; + + icm4268x_emul_get_reg(target, REG_ACCEL_CONFIG0, ®, 1); + + switch ((reg & MASK_ACCEL_UI_FS_SEL) >> 5) { + case ICM42686_BIT_ACCEL_UI_FS_32: + fs_g_out = 32; + sensitivity_out = 1024; + /* shift is based on `fs_g * 9.8` since the final numbers will be in SI units of + * m/s^2, not g's + */ + shift_out = 9; + break; + case ICM42686_BIT_ACCEL_UI_FS_16: + fs_g_out = 16; + sensitivity_out = 2048; + shift_out = 8; + break; + case ICM42686_BIT_ACCEL_UI_FS_8: + fs_g_out = 8; + sensitivity_out = 4096; + shift_out = 7; + break; + case ICM42686_BIT_ACCEL_UI_FS_4: + fs_g_out = 4; + sensitivity_out = 8192; + shift_out = 6; + break; + case ICM42686_BIT_ACCEL_UI_FS_2: + fs_g_out = 2; + sensitivity_out = 16384; + shift_out = 5; + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_g) { + *fs_g = fs_g_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Get current full-scale range in g's based on register config, along with corresponding + * sensitivity and shift. See datasheet section 3.2, table 2. + */ +static void icm42688_emul_get_accel_settings(const struct emul *target, int *fs_g, int *sensitivity, + int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_g_out; + int8_t shift_out; + + icm4268x_emul_get_reg(target, REG_ACCEL_CONFIG0, ®, 1); + + switch ((reg & MASK_ACCEL_UI_FS_SEL) >> 5) { + case ICM42688_BIT_ACCEL_UI_FS_16: + fs_g_out = 16; + sensitivity_out = 2048; + /* shift is based on `fs_g * 9.8` since the final numbers will be in SI units of + * m/s^2, not g's + */ + shift_out = 8; + break; + case ICM42688_BIT_ACCEL_UI_FS_8: + fs_g_out = 8; + sensitivity_out = 4096; + shift_out = 7; + break; + case ICM42688_BIT_ACCEL_UI_FS_4: + fs_g_out = 4; + sensitivity_out = 8192; + shift_out = 6; + break; + case ICM42688_BIT_ACCEL_UI_FS_2: + fs_g_out = 2; + sensitivity_out = 16384; + shift_out = 5; + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_g) { + *fs_g = fs_g_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Helper function for calculating accelerometer ranges. Considers the current full-scale + * register config (i.e. +/-2g, +/-4g, etc...) + */ +static void icm42686_emul_get_accel_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + int fs_g; + int sensitivity; + + icm42686_emul_get_accel_settings(target, &fs_g, &sensitivity, shift); + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_G * Q31_SCALE / sensitivity / 1000000LL / 2) >> *shift; + *upper = (fs_g * SENSOR_G * Q31_SCALE / 1000000LL) >> *shift; + *lower = -*upper; +} + +/** + * @brief Helper function for calculating accelerometer ranges. Considers the current full-scale + * register config (i.e. +/-2g, +/-4g, etc...) + */ +static void icm42688_emul_get_accel_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + int fs_g; + int sensitivity; + + icm42688_emul_get_accel_settings(target, &fs_g, &sensitivity, shift); + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_G * Q31_SCALE / sensitivity / 1000000LL / 2) >> *shift; + *upper = (fs_g * SENSOR_G * Q31_SCALE / 1000000LL) >> *shift; + *lower = -*upper; +} + +/** + * @brief Get current full-scale gyro range in milli-degrees per second based on register config, + * along with corresponding sensitivity and shift. See datasheet section 3.1, table 1. + */ +static void icm42686_emul_get_gyro_settings(const struct emul *target, int *fs_mdps, + int *sensitivity, int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_mdps_out; + int8_t shift_out; + + icm4268x_emul_get_reg(target, REG_GYRO_CONFIG0, ®, 1); + + switch ((reg & MASK_GYRO_UI_FS_SEL) >> 5) { + case ICM42686_BIT_GYRO_UI_FS_4000: + /* Milli-degrees per second */ + fs_mdps_out = 4000000; + /* 10x LSBs/deg/s */ + sensitivity_out = 82; + /* Shifts are based on rad/s: `(fs_mdps * pi / 180 / 1000)` */ + shift_out = 7; /* +/- 69.81318 */ + break; + case ICM42686_BIT_GYRO_UI_FS_2000: + fs_mdps_out = 2000000; + sensitivity_out = 164; + shift_out = 6; /* +/- 34.90659 */ + break; + case ICM42686_BIT_GYRO_UI_FS_1000: + fs_mdps_out = 1000000; + sensitivity_out = 328; + shift_out = 5; /* +/- 17.44444 */ + break; + case ICM42686_BIT_GYRO_UI_FS_500: + fs_mdps_out = 500000; + sensitivity_out = 655; + shift_out = 4; /* +/- 8.72222 */ + break; + case ICM42686_BIT_GYRO_UI_FS_250: + fs_mdps_out = 250000; + sensitivity_out = 1310; + shift_out = 3; /* +/- 4.36111 */ + break; + case ICM42686_BIT_GYRO_UI_FS_125: + fs_mdps_out = 125000; + sensitivity_out = 2620; + shift_out = 2; /* +/- 2.18055 */ + break; + case ICM42686_BIT_GYRO_UI_FS_62_5: + fs_mdps_out = 62500; + sensitivity_out = 5243; + shift_out = 1; /* +/- 1.09027 */ + break; + case ICM42686_BIT_GYRO_UI_FS_31_25: + fs_mdps_out = 31250; + sensitivity_out = 10486; + shift_out = 0; /* +/- 0.54513 */ + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_mdps) { + *fs_mdps = fs_mdps_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Get current full-scale gyro range in milli-degrees per second based on register config, + * along with corresponding sensitivity and shift. See datasheet section 3.1, table 1. + */ +static void icm42688_emul_get_gyro_settings(const struct emul *target, int *fs_mdps, + int *sensitivity, int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_mdps_out; + int8_t shift_out; + + icm4268x_emul_get_reg(target, REG_GYRO_CONFIG0, ®, 1); + + switch ((reg & MASK_GYRO_UI_FS_SEL) >> 5) { + case ICM42688_BIT_GYRO_UI_FS_2000: + fs_mdps_out = 2000000; + sensitivity_out = 164; + shift_out = 6; /* +/- 34.90659 */ + break; + case ICM42688_BIT_GYRO_UI_FS_1000: + fs_mdps_out = 1000000; + sensitivity_out = 328; + shift_out = 5; /* +/- 17.44444 */ + break; + case ICM42688_BIT_GYRO_UI_FS_500: + fs_mdps_out = 500000; + sensitivity_out = 655; + shift_out = 4; /* +/- 8.72222 */ + break; + case ICM42688_BIT_GYRO_UI_FS_250: + fs_mdps_out = 250000; + sensitivity_out = 1310; + shift_out = 3; /* +/- 4.36111 */ + break; + case ICM42688_BIT_GYRO_UI_FS_125: + fs_mdps_out = 125000; + sensitivity_out = 2620; + shift_out = 2; /* +/- 2.18055 */ + break; + case ICM42688_BIT_GYRO_UI_FS_62_5: + fs_mdps_out = 62500; + sensitivity_out = 5243; + shift_out = 1; /* +/- 1.09027 */ + break; + case ICM42688_BIT_GYRO_UI_FS_31_25: + fs_mdps_out = 31250; + sensitivity_out = 10486; + shift_out = 0; /* +/- 0.54513 */ + break; + case ICM42688_BIT_GYRO_UI_FS_15_625: + fs_mdps_out = 15625; + sensitivity_out = 20972; + shift_out = -1; /* +/- 0.27256 */ + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_mdps) { + *fs_mdps = fs_mdps_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Helper function for calculating gyroscope ranges. Considers the current full-scale + * register config + */ +static void icm42686_emul_get_gyro_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + /* millidegrees/second */ + int fs_mdps; + /* 10x LSBs per degrees/second*/ + int sensitivity; + + icm42686_emul_get_gyro_settings(target, &fs_mdps, &sensitivity, shift); + + /* Reduce the actual range of gyroscope values. Some full-scale ranges actually exceed the + * size of an int16 by a small margin. For example, FS_SEL=0 has a +/-2000 deg/s range with + * 16.4 bits/deg/s sensitivity (Section 3.1, Table 1). This works out to register values of + * +/-2000 * 16.4 = +/-32800. This will cause the expected value to get clipped when + * setting the register and throw off the actual reading. Therefore, scale down the range + * to 99% to avoid the top and bottom edges. + */ + + fs_mdps *= 0.99; + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_PI * Q31_SCALE * 10LL / 1000000LL / 180LL / sensitivity / 2LL) >> + *shift; + *upper = (((fs_mdps * SENSOR_PI / 1000000LL) * Q31_SCALE) / 1000LL / 180LL) >> *shift; + *lower = -*upper; +} + +/** + * @brief Helper function for calculating gyroscope ranges. Considers the current full-scale + * register config + */ +static void icm42688_emul_get_gyro_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + /* millidegrees/second */ + int fs_mdps; + /* 10x LSBs per degrees/second*/ + int sensitivity; + + icm42688_emul_get_gyro_settings(target, &fs_mdps, &sensitivity, shift); + + /* Reduce the actual range of gyroscope values. Some full-scale ranges actually exceed the + * size of an int16 by a small margin. For example, FS_SEL=0 has a +/-2000 deg/s range with + * 16.4 bits/deg/s sensitivity (Section 3.1, Table 1). This works out to register values of + * +/-2000 * 16.4 = +/-32800. This will cause the expected value to get clipped when + * setting the register and throw off the actual reading. Therefore, scale down the range + * to 99% to avoid the top and bottom edges. + */ + + fs_mdps *= 0.99; + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_PI * Q31_SCALE * 10LL / 1000000LL / 180LL / sensitivity / 2LL) >> + *shift; + *upper = (((fs_mdps * SENSOR_PI / 1000000LL) * Q31_SCALE) / 1000LL / 180LL) >> *shift; + *lower = -*upper; +} + +static int icm42686_emul_backend_get_sample_range(const struct emul *target, + struct sensor_chan_spec ch, q31_t *lower, + q31_t *upper, q31_t *epsilon, int8_t *shift) +{ + if (!lower || !upper || !epsilon || !shift) { + return -EINVAL; + } + + switch (ch.chan_type) { + case SENSOR_CHAN_DIE_TEMP: + /* degrees C = ([16-bit signed temp_data register] / 132.48) + 25 */ + *shift = 9; + *lower = (int64_t)(-222.342995169 * Q31_SCALE) >> *shift; + *upper = (int64_t)(272.33544686 * Q31_SCALE) >> *shift; + *epsilon = (int64_t)(0.0076 * Q31_SCALE) >> *shift; + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42686_emul_get_accel_ranges(target, lower, upper, epsilon, shift); + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42686_emul_get_gyro_ranges(target, lower, upper, epsilon, shift); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int icm42688_emul_backend_get_sample_range(const struct emul *target, + struct sensor_chan_spec ch, q31_t *lower, + q31_t *upper, q31_t *epsilon, int8_t *shift) +{ + if (!lower || !upper || !epsilon || !shift) { + return -EINVAL; + } + + switch (ch.chan_type) { + case SENSOR_CHAN_DIE_TEMP: + /* degrees C = ([16-bit signed temp_data register] / 132.48) + 25 */ + *shift = 9; + *lower = (int64_t)(-222.342995169 * Q31_SCALE) >> *shift; + *upper = (int64_t)(272.33544686 * Q31_SCALE) >> *shift; + *epsilon = (int64_t)(0.0076 * Q31_SCALE) >> *shift; + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42688_emul_get_accel_ranges(target, lower, upper, epsilon, shift); + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42688_emul_get_gyro_ranges(target, lower, upper, epsilon, shift); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int icm42686_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, + const q31_t *value, int8_t shift) +{ + if (!target || !target->data) { + return -EINVAL; + } + + struct icm4268x_emul_data *data = target->data; + + int sensitivity; + uint8_t reg_addr; + int32_t reg_val; + int64_t value_unshifted = + shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); + + switch (ch.chan_type) { + case SENSOR_CHAN_DIE_TEMP: + reg_addr = REG_TEMP_DATA1; + reg_val = ((value_unshifted - (25 * Q31_SCALE)) * 13248) / (100 * Q31_SCALE); + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (ch.chan_type) { + case SENSOR_CHAN_ACCEL_X: + reg_addr = REG_ACCEL_DATA_X1; + break; + case SENSOR_CHAN_ACCEL_Y: + reg_addr = REG_ACCEL_DATA_Y1; + break; + case SENSOR_CHAN_ACCEL_Z: + reg_addr = REG_ACCEL_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42686_emul_get_accel_settings(target, NULL, &sensitivity, NULL); + reg_val = ((value_unshifted * sensitivity / Q31_SCALE) * 1000000LL) / SENSOR_G; + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (ch.chan_type) { + case SENSOR_CHAN_GYRO_X: + reg_addr = REG_GYRO_DATA_X1; + break; + case SENSOR_CHAN_GYRO_Y: + reg_addr = REG_GYRO_DATA_Y1; + break; + case SENSOR_CHAN_GYRO_Z: + reg_addr = REG_GYRO_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42686_emul_get_gyro_settings(target, NULL, &sensitivity, NULL); + reg_val = + CLAMP((((value_unshifted * sensitivity * 180LL) / Q31_SCALE) * 1000000LL) / + SENSOR_PI / 10LL, + INT16_MIN, INT16_MAX); + break; + default: + return -ENOTSUP; + } + + data->reg[reg_addr] = (reg_val >> 8) & 0xFF; + data->reg[reg_addr + 1] = reg_val & 0xFF; + + /* Set data ready flag */ + data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_DATA_RDY; + + return 0; +} + +static int icm42688_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, + const q31_t *value, int8_t shift) +{ + if (!target || !target->data) { + return -EINVAL; + } + + struct icm4268x_emul_data *data = target->data; + + int sensitivity; + uint8_t reg_addr; + int32_t reg_val; + int64_t value_unshifted = + shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); + + switch (ch.chan_type) { + case SENSOR_CHAN_DIE_TEMP: + reg_addr = REG_TEMP_DATA1; + reg_val = ((value_unshifted - (25 * Q31_SCALE)) * 13248) / (100 * Q31_SCALE); + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (ch.chan_type) { + case SENSOR_CHAN_ACCEL_X: + reg_addr = REG_ACCEL_DATA_X1; + break; + case SENSOR_CHAN_ACCEL_Y: + reg_addr = REG_ACCEL_DATA_Y1; + break; + case SENSOR_CHAN_ACCEL_Z: + reg_addr = REG_ACCEL_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42688_emul_get_accel_settings(target, NULL, &sensitivity, NULL); + reg_val = ((value_unshifted * sensitivity / Q31_SCALE) * 1000000LL) / SENSOR_G; + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (ch.chan_type) { + case SENSOR_CHAN_GYRO_X: + reg_addr = REG_GYRO_DATA_X1; + break; + case SENSOR_CHAN_GYRO_Y: + reg_addr = REG_GYRO_DATA_Y1; + break; + case SENSOR_CHAN_GYRO_Z: + reg_addr = REG_GYRO_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42688_emul_get_gyro_settings(target, NULL, &sensitivity, NULL); + reg_val = + CLAMP((((value_unshifted * sensitivity * 180LL) / Q31_SCALE) * 1000000LL) / + SENSOR_PI / 10LL, + INT16_MIN, INT16_MAX); + break; + default: + return -ENOTSUP; + } + + data->reg[reg_addr] = (reg_val >> 8) & 0xFF; + data->reg[reg_addr + 1] = reg_val & 0xFF; + + /* Set data ready flag */ + data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_DATA_RDY; + + return 0; +} + +static const struct emul_sensor_driver_api icm42686_emul_sensor_driver_api = { + .set_channel = icm42686_emul_backend_set_channel, + .get_sample_range = icm42686_emul_backend_get_sample_range, +}; + +static const struct emul_sensor_driver_api icm42688_emul_sensor_driver_api = { + .set_channel = icm42688_emul_backend_set_channel, + .get_sample_range = icm42688_emul_backend_get_sample_range, +}; + +#define ICM4268X_EMUL_DEFINE(n, name, who_am_i, api) \ + EMUL_DT_INST_DEFINE(n, name##_emul_init, &icm4268x_emul_data_##n, \ + &icm4268x_emul_cfg_##n, &api, &name##_emul_sensor_driver_api) + +#define ICM4268X_EMUL_SPI(n, name, who_am_i) \ + static struct icm4268x_emul_data icm4268x_emul_data_##n; \ + static const struct icm4268x_emul_cfg icm4268x_emul_cfg_##n; \ + ICM4268X_EMUL_DEFINE(n, name, who_am_i, name##_emul_spi_api) + +#define ICM42688_EMUL_SPI(n) \ + ICM4268X_EMUL_SPI(n, icm42688, WHO_AM_I_ICM42688) + +#define ICM42686_EMUL_SPI(n) \ + ICM4268X_EMUL_SPI(n, icm42686, WHO_AM_I_ICM42686) + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42686 +DT_INST_FOREACH_STATUS_OKAY(ICM42686_EMUL_SPI) + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT invensense_icm42688 +DT_INST_FOREACH_STATUS_OKAY(ICM42688_EMUL_SPI) diff --git a/drivers/sensor/tdk/icm42688/icm42688_emul.h b/drivers/sensor/tdk/icm4268x/icm4268x_emul.h similarity index 71% rename from drivers/sensor/tdk/icm42688/icm42688_emul.h rename to drivers/sensor/tdk/icm4268x/icm4268x_emul.h index 6c31fee8786c5..b0725cdace7b4 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_emul.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x_emul.h @@ -1,10 +1,11 @@ /* * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP * SPDX-License-Identifier: Apache-2.0 */ -#ifndef DRIVERS_SENSOR_ICM42688_ICM42688_EMUL_H -#define DRIVERS_SENSOR_ICM42688_ICM42688_EMUL_H +#ifndef DRIVERS_SENSOR_ICM4268X_ICM4268X_EMUL_H +#define DRIVERS_SENSOR_ICM4268X_ICM4268X_EMUL_H #include @@ -16,7 +17,7 @@ * @param in One or more bytes to write to the registers * @param count The number of bytes to write */ -void icm42688_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *in, +void icm4268x_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *in, size_t count); /** @@ -27,6 +28,6 @@ void icm42688_emul_set_reg(const struct emul *target, uint8_t reg_addr, const ui * @param out Buffer to write the register values into * @param count The number of bytes to read */ -void icm42688_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *out, size_t count); +void icm4268x_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *out, size_t count); -#endif /* DRIVERS_SENSOR_ICM42688_ICM42688_EMUL_H */ +#endif /* DRIVERS_SENSOR_ICM4268X_ICM4268X_EMUL_H */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_reg.h b/drivers/sensor/tdk/icm4268x/icm4268x_reg.h similarity index 72% rename from drivers/sensor/tdk/icm42688/icm42688_reg.h rename to drivers/sensor/tdk/icm4268x/icm4268x_reg.h index 5f3b58f0b3c07..bac83c35ae5cf 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_reg.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x_reg.h @@ -1,11 +1,12 @@ /* * Copyright (c) 2022 Intel Corporation + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_REG_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_REG_H_ #include @@ -117,6 +118,9 @@ #define REG_INTF_CONFIG6 (REG_BANK1_OFFSET | 0x7C) /* Bank 2 */ +#define ACCEL_CONFIG_STATIC2 (REG_BANK2_OFFSET | 0x03) +#define ACCEL_CONFIG_STATIC3 (REG_BANK2_OFFSET | 0x04) +#define ACCEL_CONFIG_STATIC4 (REG_BANK2_OFFSET | 0x05) /* Bank 4 */ #define REG_INT_SOURCE6 (REG_BANK4_OFFSET | 0x77) @@ -167,6 +171,13 @@ #define BIT_INT_STATUS_STEP_CNT_OVFL BIT(4) #define BIT_INT_STATUS_STEP_DET BIT(5) +/* Bank0 REG_TMST_CONFIG */ +#define BIT_TMST_EN BIT(0) +#define BIT_TMST_FSYNC_EN BIT(1) +#define BIT_TMST_DELTA_EN BIT(2) +#define BIT_TMST_RES BIT(3) +#define BIT_TMST_TO_REGS_EN BIT(4) + /* Bank0 REG_SIGNAL_PATH_RESET */ #define BIT_FIFO_FLUSH BIT(1) #define BIT_TMST_STROBE BIT(2) @@ -176,8 +187,8 @@ /* Bank0 REG_INTF_CONFIG0 */ #define MASK_UI_SIFS_CFG GENMASK(1, 0) -#define BIT_UI_SIFS_CFG_DISABLE_SPI 0x10 -#define BIT_UI_SIFS_CFG_DISABLE_I2C 0x11 +#define BIT_UI_SIFS_CFG_DISABLE_SPI 0x02 +#define BIT_UI_SIFS_CFG_DISABLE_I2C 0x03 #define BIT_SENSOR_DATA_ENDIAN BIT(4) #define BIT_FIFO_COUNT_ENDIAN BIT(5) #define BIT_FIFO_COUNT_REC BIT(6) @@ -190,6 +201,7 @@ #define BIT_CLKSEL_DISABLE 0x11 #define BIT_RTC_MODE BIT(2) #define BIT_ACCEL_LP_CLK_SEL BIT(3) +#define BIT_AFSR_SET BIT(6) /* Bank0 REG_PWR_MGMT_0 */ #define MASK_ACCEL_MODE GENMASK(1, 0) @@ -205,14 +217,24 @@ /* Bank0 REG_GYRO_CONFIG0 */ #define MASK_GYRO_UI_FS_SEL GENMASK(7, 5) -#define BIT_GYRO_UI_FS_2000 0x00 -#define BIT_GYRO_UI_FS_1000 0x01 -#define BIT_GYRO_UI_FS_500 0x02 -#define BIT_GYRO_UI_FS_250 0x03 -#define BIT_GYRO_UI_FS_125 0x04 -#define BIT_GYRO_UI_FS_62_5 0x05 -#define BIT_GYRO_UI_FS_31_25 0x06 -#define BIT_GYRO_UI_FS_15_625 0x07 +#define ICM42686_BIT_GYRO_UI_FS_4000 0x00 +#define ICM42686_BIT_GYRO_UI_FS_2000 0x01 +#define ICM42686_BIT_GYRO_UI_FS_1000 0x02 +#define ICM42686_BIT_GYRO_UI_FS_500 0x03 +#define ICM42686_BIT_GYRO_UI_FS_250 0x04 +#define ICM42686_BIT_GYRO_UI_FS_125 0x05 +#define ICM42686_BIT_GYRO_UI_FS_62_5 0x06 +#define ICM42686_BIT_GYRO_UI_FS_31_25 0x07 + +#define ICM42688_BIT_GYRO_UI_FS_2000 0x00 +#define ICM42688_BIT_GYRO_UI_FS_1000 0x01 +#define ICM42688_BIT_GYRO_UI_FS_500 0x02 +#define ICM42688_BIT_GYRO_UI_FS_250 0x03 +#define ICM42688_BIT_GYRO_UI_FS_125 0x04 +#define ICM42688_BIT_GYRO_UI_FS_62_5 0x05 +#define ICM42688_BIT_GYRO_UI_FS_31_25 0x06 +#define ICM42688_BIT_GYRO_UI_FS_15_625 0x07 + #define MASK_GYRO_ODR GENMASK(3, 0) #define BIT_GYRO_ODR_32000 0x01 #define BIT_GYRO_ODR_16000 0x02 @@ -229,10 +251,17 @@ /* Bank0 REG_ACCEL_CONFIG0 */ #define MASK_ACCEL_UI_FS_SEL GENMASK(7, 5) -#define BIT_ACCEL_UI_FS_16 0x00 -#define BIT_ACCEL_UI_FS_8 0x01 -#define BIT_ACCEL_UI_FS_4 0x02 -#define BIT_ACCEL_UI_FS_2 0x03 +#define ICM42686_BIT_ACCEL_UI_FS_32 0x00 +#define ICM42686_BIT_ACCEL_UI_FS_16 0x01 +#define ICM42686_BIT_ACCEL_UI_FS_8 0x02 +#define ICM42686_BIT_ACCEL_UI_FS_4 0x03 +#define ICM42686_BIT_ACCEL_UI_FS_2 0x04 + +#define ICM42688_BIT_ACCEL_UI_FS_16 0x00 +#define ICM42688_BIT_ACCEL_UI_FS_8 0x01 +#define ICM42688_BIT_ACCEL_UI_FS_4 0x02 +#define ICM42688_BIT_ACCEL_UI_FS_2 0x03 + #define MASK_ACCEL_ODR GENMASK(3, 0) #define BIT_ACCEL_ODR_32000 0x01 #define BIT_ACCEL_ODR_16000 0x02 @@ -254,9 +283,9 @@ #define BIT_FIFO_WM_GT_TH BIT(5) #define BIT_FIFO_HIRES_EN BIT(4) #define BIT_FIFO_TMST_FSYNC_EN BIT(3) -#define BIT_FIFO_GYRO_EN BIT(2) -#define BIT_FIFO_ACCEL_EN BIT(1) -#define BIT_FIFO_TEMP_EN BIT(0) +#define BIT_FIFO_TEMP_EN BIT(2) +#define BIT_FIFO_GYRO_EN BIT(1) +#define BIT_FIFO_ACCEL_EN BIT(0) /* Bank0 INT_SOURCE0 */ #define BIT_UI_FSYNC_INT1_EN BIT(6) @@ -271,6 +300,15 @@ #define MASK_FSYNC_UI_SEL GENMASK(6, 4) #define BIT_FSYNC_UI +/* Bank0 REG_INT_CONFIG0 */ +#define MASK_FIFO_THS_INT_CLEAR GENMASK(3, 2) +#define BIT_THS_INT_CLR_ON_STSRD BIT(2) +#define BIT_THS_INT_CLR_ON_FIFORD BIT(3) + +#define MASK_FIFO_FULL_INT_CLR GENMASK(1, 0) +#define BIT_FULL_INT_CLR_ON_STSRD BIT(0) +#define BIT_FULL_INT_CLR_ON_FIFORD BIT(1) + /* Bank0 REG_INT_CONFIG1 */ #define BIT_INT_TPULSE_DURATION BIT(6) #define BIT_INT_TDEASSERT_DISABLE BIT(5) @@ -278,6 +316,7 @@ /* misc. defines */ #define WHO_AM_I_ICM42688 0x47 +#define WHO_AM_I_ICM42686 0x44 #define MIN_ACCEL_SENS_SHIFT 11 #define ACCEL_DATA_SIZE 6 #define GYRO_DATA_SIZE 6 @@ -294,4 +333,54 @@ #define FIFO_HEADER_ODR_ACCEL BIT(1) #define FIFO_HEADER_ODR_GYRO BIT(0) -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ */ +/* Bank2 ACCEL_CONFIG_STATIC2 */ +#define MASK_ACCEL_AAF_DELT GENMASK(6, 1) + +#define ACCEL_AAF_DELT_SET_585HZ BIT(1) | BIT(3) | BIT(4) +#define ACCEL_AAF_DELT_CLEAR_585HZ BIT(2) | BIT(5) | BIT(6) +#define ACCEL_AAF_DIS BIT(0) + +/* Bank2 ACCEL_CONFIG_STATIC3 */ +#define MASK_ACCEL_AAF_DELTSQR_LSB GENMASK(7, 0) + +#define ACCEL_AAF_DELTSQR_LSB_SET_585HZ BIT(1) | BIT(3) | BIT(5) | BIT(7) +#define ACCEL_AAF_DELTSQR_LSB_CLEAR_585HZ BIT(0) | BIT(2) | BIT(4) | BIT(6) + +/* Bank2 ACCEL_CONFIG_STATIC4 */ +#define MASK_ACCEL_AAF_BITSHIFT GENMASK(7, 4) + +#define ACCEL_AAF_BITSHIFT_SET_585HZ BIT(7) +#define ACCEL_AAF_BITSHIFT_CLEAR_585HZ BIT(4) | BIT(5) | BIT(6) + +#define MASK_ACCEL_AAF_DELTSQR_MSB GENMASK(3, 0) +#define ACCEL_AAF_DELTSQR_SET_MSB 0 +#define ACCEL_AAF_DELTSQR_CLEAR_MSB BIT(0) | BIT(1) | BIT(2) | BIT(3) + +/* Bank1 GYRO_CONFIG_STATIC2 */ +#define GYRO_AAF_DIS BIT(1) +#define GYRO_NF_DIS BIT(0) + +/* Bank1 GYRO_CONFIG_STATIC3 */ +#define MASK_GYRO_AAF_DELT GENMASK(5, 0) + +#define GYRO_AAF_DELT_SET_585HZ BIT(0) | BIT(2) | BIT(3) +#define GYRO_AAF_DELT_CLEAR_585HZ BIT(1) | BIT(4) | BIT(5) + +/* Bank1 GYRO_CONFIG_STATIC4 */ +#define MASK_GYRO_AAF_DELTSQR_LSB GENMASK(7, 0) + +#define GYRO_AAF_DELTSQR_LSB_SET_585HZ BIT(1) | BIT(3) | BIT(5) | BIT(7) +#define GYRO_AAF_DELTSQR_LSB_CLEAR_585HZ BIT(0) | BIT(2) | BIT(4) | BIT(6) + +/* Bank1 GYRO_CONFIG_STATIC5 */ +#define MASK_GYRO_AAF_BITSHIFT GENMASK(7, 4) + +#define GYRO_AAF_BITSHIFT_SET_585HZ BIT(7) +#define GYRO_AAF_BITSHIFT_CLEAR_585HZ BIT(4) | BIT(5) | BIT(6) + +#define MASK_GYRO_AAF_DELTSQR_MSB GENMASK(3, 0) + +#define GYRO_AAF_DELTSQR_MSB_SET_585HZ 0 +#define GYRO_AAF_DELTSQR_MSB_CLEAR_585HZ BIT(0) | BIT(1) | BIT(2) | BIT(3) + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_REG_H_ */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c similarity index 59% rename from drivers/sensor/tdk/icm42688/icm42688_rtio.c rename to drivers/sensor/tdk/icm4268x/icm4268x_rtio.c index 50ca1160da0e9..43c9f8ce83739 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c @@ -7,22 +7,22 @@ #include #include -#include "icm42688.h" -#include "icm42688_decoder.h" -#include "icm42688_reg.h" -#include "icm42688_rtio.h" -#include "icm42688_spi.h" +#include "icm4268x.h" +#include "icm4268x_decoder.h" +#include "icm4268x_reg.h" +#include "icm4268x_rtio.h" +#include "icm4268x_spi.h" #include -LOG_MODULE_REGISTER(ICM42688_RTIO, CONFIG_SENSOR_LOG_LEVEL); +LOG_MODULE_REGISTER(ICM4268X_RTIO, CONFIG_SENSOR_LOG_LEVEL); -static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings[7]) +static int icm4268x_rtio_sample_fetch(const struct device *dev, int16_t readings[7]) { uint8_t status; - const struct icm42688_dev_cfg *cfg = dev->config; + const struct icm4268x_dev_cfg *cfg = dev->config; uint8_t *buffer = (uint8_t *)readings; - int res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); + int res = icm4268x_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); if (res) { return res; @@ -32,7 +32,7 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings return -EBUSY; } - res = icm42688_read_all(dev, buffer); + res = icm4268x_read_all(dev, buffer); if (res) { return res; @@ -45,16 +45,16 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings return 0; } -static void icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +static void icm4268x_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; - uint32_t min_buf_len = sizeof(struct icm42688_encoded_data); + uint32_t min_buf_len = sizeof(struct icm4268x_encoded_data); int rc; uint8_t *buf; uint32_t buf_len; - struct icm42688_encoded_data *edata; + struct icm4268x_encoded_data *edata; /* Get the buffer for the frame, it may be allocated dynamically by the rtio context */ rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len); @@ -64,11 +64,11 @@ static void icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev return; } - edata = (struct icm42688_encoded_data *)buf; + edata = (struct icm4268x_encoded_data *)buf; - icm42688_encode(dev, channels, num_channels, buf); + icm4268x_encode(dev, channels, num_channels, buf); - rc = icm42688_rtio_sample_fetch(dev, edata->readings); + rc = icm4268x_rtio_sample_fetch(dev, edata->readings); /* Check that the fetch succeeded */ if (rc != 0) { LOG_ERR("Failed to fetch samples"); @@ -79,27 +79,27 @@ static void icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev rtio_iodev_sqe_ok(iodev_sqe, 0); } -void icm42688_submit_sync(struct rtio_iodev_sqe *iodev_sqe) +void icm4268x_submit_sync(struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const struct device *dev = cfg->sensor; if (!cfg->is_streaming) { - icm42688_submit_one_shot(dev, iodev_sqe); - } else if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { - icm42688_submit_stream(dev, iodev_sqe); + icm4268x_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_ICM4268X_STREAM)) { + icm4268x_submit_stream(dev, iodev_sqe); } else { rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); } } -void icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +void icm4268x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { struct rtio_work_req *req = rtio_work_req_alloc(); __ASSERT_NO_MSG(req); - rtio_work_req_submit(req, iodev_sqe, icm42688_submit_sync); + rtio_work_req_submit(req, iodev_sqe, icm4268x_submit_sync); } -BUILD_ASSERT(sizeof(struct icm42688_decoder_header) == 9); +BUILD_ASSERT(sizeof(struct icm4268x_decoder_header) == 9); diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_rtio.h b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.h new file mode 100644 index 0000000000000..a28ea3fb32e33 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_RTIO_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_RTIO_H_ + +#include +#include + +void icm4268x_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +void icm4268x_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +void icm4268x_fifo_event(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_RTIO_H_ */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c similarity index 82% rename from drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c rename to drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c index fd901742309dd..7c3598866b1ec 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c @@ -1,23 +1,24 @@ /* * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include -#include "icm42688.h" -#include "icm42688_decoder.h" -#include "icm42688_reg.h" -#include "icm42688_rtio.h" +#include "icm4268x.h" +#include "icm4268x_decoder.h" +#include "icm4268x_reg.h" +#include "icm4268x_rtio.h" -LOG_MODULE_DECLARE(ICM42688_RTIO); +LOG_MODULE_DECLARE(ICM4268X_RTIO); -void icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe) +void icm4268x_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; - struct icm42688_dev_data *data = sensor->data; - struct icm42688_cfg new_config = data->cfg; + struct icm4268x_dev_data *data = sensor->data; + struct icm4268x_cfg new_config = data->cfg; new_config.interrupt1_drdy = false; new_config.interrupt1_fifo_ths = false; @@ -43,7 +44,7 @@ void icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe * if (new_config.interrupt1_drdy != data->cfg.interrupt1_drdy || new_config.interrupt1_fifo_ths != data->cfg.interrupt1_fifo_ths || new_config.interrupt1_fifo_full != data->cfg.interrupt1_fifo_full) { - int rc = icm42688_safely_configure(sensor, &new_config); + int rc = icm4268x_safely_configure(sensor, &new_config); if (rc != 0) { LOG_ERR("Failed to configure sensor"); @@ -55,11 +56,11 @@ void icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe * data->streaming_sqe = iodev_sqe; } -static void icm42688_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +static void icm4268x_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) { const struct device *dev = arg; - struct icm42688_dev_data *drv_data = dev->data; - const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct icm4268x_dev_data *drv_data = dev->data; + const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); @@ -67,11 +68,11 @@ static void icm42688_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, voi gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); } -static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) { const struct device *dev = arg; - struct icm42688_dev_data *drv_data = dev->data; - const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct icm4268x_dev_data *drv_data = dev->data; + const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); @@ -91,8 +92,8 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v } const size_t packet_size = drv_data->cfg.fifo_hires ? 20 : 16; - const size_t min_read_size = sizeof(struct icm42688_fifo_data) + packet_size; - const size_t ideal_read_size = sizeof(struct icm42688_fifo_data) + fifo_count; + const size_t min_read_size = sizeof(struct icm4268x_fifo_data) + packet_size; + const size_t ideal_read_size = sizeof(struct icm4268x_fifo_data) + fifo_count; uint8_t *buf; uint32_t buf_len; @@ -108,7 +109,7 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v /* TODO is packet format even needed? the fifo has a header per packet * already */ - struct icm42688_fifo_data hdr = { + struct icm4268x_fifo_data hdr = { .header = { .is_fifo = true, .gyro_fs = drv_data->cfg.gyro_fs, @@ -128,7 +129,7 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v uint32_t pkts = read_len / packet_size; read_len = pkts * packet_size; - ((struct icm42688_fifo_data *)buf)->fifo_count = read_len; + ((struct icm4268x_fifo_data *)buf)->fifo_count = read_len; __ASSERT_NO_MSG(read_len % pkt_size == 0); @@ -157,13 +158,13 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v rtio_sqe_prep_read(read_fifo_data, spi_iodev, RTIO_PRIO_NORM, read_buf, read_len, iodev_sqe); read_fifo_data->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(complete_op, icm42688_complete_cb, (void *)dev, iodev_sqe); + rtio_sqe_prep_callback(complete_op, icm4268x_complete_cb, (void *)dev, iodev_sqe); rtio_submit(r, 0); } static struct sensor_stream_trigger * -icm42688_get_read_config_trigger(const struct sensor_read_config *cfg, +icm4268x_get_read_config_trigger(const struct sensor_read_config *cfg, enum sensor_trigger_type trig) { for (int i = 0; i < cfg->count; ++i) { @@ -175,11 +176,11 @@ icm42688_get_read_config_trigger(const struct sensor_read_config *cfg, return NULL; } -static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg) +static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg) { const struct device *dev = arg; - struct icm42688_dev_data *drv_data = dev->data; - const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct icm4268x_dev_data *drv_data = dev->data; + const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; struct sensor_read_config *read_config; @@ -197,12 +198,12 @@ static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, v } struct sensor_stream_trigger *fifo_ths_cfg = - icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); + icm4268x_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); bool has_fifo_ths_trig = fifo_ths_cfg != NULL && FIELD_GET(BIT_INT_STATUS_FIFO_THS, drv_data->int_status) != 0; struct sensor_stream_trigger *fifo_full_cfg = - icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); + icm4268x_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); bool has_fifo_full_trig = fifo_full_cfg != NULL && FIELD_GET(BIT_INT_STATUS_FIFO_FULL, drv_data->int_status) != 0; @@ -240,13 +241,13 @@ static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, v /* Clear streaming_sqe since we're done with the call */ drv_data->streaming_sqe = NULL; - if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm42688_fifo_data), - sizeof(struct icm42688_fifo_data), &buf, &buf_len) != 0) { + if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm4268x_fifo_data), + sizeof(struct icm4268x_fifo_data), &buf, &buf_len) != 0) { rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); return; } - struct icm42688_fifo_data *data = (struct icm42688_fifo_data *)buf; + struct icm4268x_fifo_data *data = (struct icm4268x_fifo_data *)buf; memset(buf, 0, buf_len); data->header.timestamp = drv_data->timestamp; @@ -282,14 +283,14 @@ static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, v write_fifo_count_reg->flags = RTIO_SQE_TRANSACTION; rtio_sqe_prep_read(read_fifo_count, spi_iodev, RTIO_PRIO_NORM, read_buf, 2, NULL); read_fifo_count->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(check_fifo_count, icm42688_fifo_count_cb, arg, NULL); + rtio_sqe_prep_callback(check_fifo_count, icm4268x_fifo_count_cb, arg, NULL); rtio_submit(r, 0); } -void icm42688_fifo_event(const struct device *dev) +void icm4268x_fifo_event(const struct device *dev) { - struct icm42688_dev_data *drv_data = dev->data; + struct icm4268x_dev_data *drv_data = dev->data; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; struct rtio *r = drv_data->r; @@ -317,6 +318,6 @@ void icm42688_fifo_event(const struct device *dev) write_int_reg->flags = RTIO_SQE_TRANSACTION; rtio_sqe_prep_read(read_int_reg, spi_iodev, RTIO_PRIO_NORM, &drv_data->int_status, 1, NULL); read_int_reg->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(check_int_status, icm42688_int_status_cb, (void *)dev, NULL); + rtio_sqe_prep_callback(check_int_status, icm4268x_int_status_cb, (void *)dev, NULL); rtio_submit(r, 0); } diff --git a/drivers/sensor/tdk/icm42688/icm42688_spi.c b/drivers/sensor/tdk/icm4268x/icm4268x_spi.c similarity index 79% rename from drivers/sensor/tdk/icm42688/icm42688_spi.c rename to drivers/sensor/tdk/icm4268x/icm4268x_spi.c index dedaf56c034fc..55535a0424758 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_spi.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_spi.c @@ -1,12 +1,13 @@ /* * Copyright (c) 2022 Intel Corporation + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include -#include "icm42688_spi.h" -#include "icm42688_reg.h" +#include "icm4268x_spi.h" +#include "icm4268x_reg.h" static inline int spi_write_register(const struct spi_dt_spec *bus, uint8_t reg, uint8_t data) { @@ -63,7 +64,7 @@ static inline int spi_read_register(const struct spi_dt_spec *bus, uint8_t reg, return spi_transceive_dt(bus, &tx, &rx); } -int icm42688_spi_read(const struct spi_dt_spec *bus, uint16_t reg, uint8_t *data, size_t len) +int icm4268x_spi_read(const struct spi_dt_spec *bus, uint16_t reg, uint8_t *data, size_t len) { int res = 0; uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); @@ -73,11 +74,11 @@ int icm42688_spi_read(const struct spi_dt_spec *bus, uint16_t reg, uint8_t *data return res; } -int icm42688_spi_update_register(const struct spi_dt_spec *bus, uint16_t reg, uint8_t mask, +int icm4268x_spi_update_register(const struct spi_dt_spec *bus, uint16_t reg, uint8_t mask, uint8_t data) { uint8_t temp = 0; - int res = icm42688_spi_read(bus, reg, &temp, 1); + int res = icm4268x_spi_read(bus, reg, &temp, 1); if (res) { return res; @@ -86,10 +87,10 @@ int icm42688_spi_update_register(const struct spi_dt_spec *bus, uint16_t reg, ui temp &= ~mask; temp |= FIELD_PREP(mask, data); - return icm42688_spi_single_write(bus, reg, temp); + return icm4268x_spi_single_write(bus, reg, temp); } -int icm42688_spi_single_write(const struct spi_dt_spec *bus, uint16_t reg, uint8_t data) +int icm4268x_spi_single_write(const struct spi_dt_spec *bus, uint16_t reg, uint8_t data) { int res = 0; uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); diff --git a/drivers/sensor/tdk/icm42688/icm42688_spi.h b/drivers/sensor/tdk/icm4268x/icm4268x_spi.h similarity index 60% rename from drivers/sensor/tdk/icm42688/icm42688_spi.h rename to drivers/sensor/tdk/icm4268x/icm4268x_spi.h index ea0a0006dcbd3..9fd62a2480a6d 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_spi.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x_spi.h @@ -1,55 +1,56 @@ /* * Copyright (c) 2022 Intel Corporation + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_SPI_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42688_SPI_H_ +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_SPI_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_SPI_H_ #include #include /** - * @brief perform a single SPI write to a ICM42688 register + * @brief perform a single SPI write to a ICM4268X register * - * this functions wraps all logic necessary to write to any of the ICM42688 registers, regardless + * this functions wraps all logic necessary to write to any of the ICM4268X registers, regardless * of which memory bank the register belongs to. * * @param bus SPI bus pointer - * @param reg address of ICM42688 register to write to + * @param reg address of ICM4268X register to write to * @param data data byte to write to register * @return int 0 on success, negative error code otherwise */ -int icm42688_spi_single_write(const struct spi_dt_spec *bus, uint16_t reg, uint8_t data); +int icm4268x_spi_single_write(const struct spi_dt_spec *bus, uint16_t reg, uint8_t data); /** - * @brief update a single ICM42688 register value + * @brief update a single ICM4268X register value * - * this functions wraps all logic necessary to update any of the ICM42688 registers, regardless + * this functions wraps all logic necessary to update any of the ICM4268X registers, regardless * of which memory bank the register belongs to. * * @param bus SPI bus pointer - * @param reg address of ICM42688 register to update + * @param reg address of ICM4268X register to update * @param mask bitmask defining which bits of the register to update * @param data new value to update register with, respecting the bitmask * @return int 0 on success, negative error code otherwise */ -int icm42688_spi_update_register(const struct spi_dt_spec *bus, uint16_t reg, uint8_t mask, +int icm4268x_spi_update_register(const struct spi_dt_spec *bus, uint16_t reg, uint8_t mask, uint8_t data); /** - * @brief read from one or more ICM42688 registers + * @brief read from one or more ICM4268X registers * - * this functions wraps all logic necessary to read from any of the ICM42688 registers, regardless + * this functions wraps all logic necessary to read from any of the ICM4268X registers, regardless * of which memory bank the register belongs to. * * @param bus SPI bus pointer - * @param reg start address of ICM42688 register(s) to read from + * @param reg start address of ICM4268X register(s) to read from * @param data pointer to byte array to read register values to * @param len number of bytes to read from the device * @return int 0 on success, negative error code otherwise */ -int icm42688_spi_read(const struct spi_dt_spec *bus, uint16_t reg, uint8_t *data, size_t len); +int icm4268x_spi_read(const struct spi_dt_spec *bus, uint16_t reg, uint8_t *data, size_t len); -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_SPI_H_ */ +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_SPI_H_ */ diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c new file mode 100644 index 0000000000000..14a4e8d4fc350 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "icm4268x.h" +#include "icm4268x_reg.h" +#include "icm4268x_rtio.h" +#include "icm4268x_spi.h" +#include "icm4268x_trigger.h" + +LOG_MODULE_DECLARE(ICM4268X, CONFIG_SENSOR_LOG_LEVEL); + +static void icm4268x_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct icm4268x_dev_data *data = CONTAINER_OF(cb, struct icm4268x_dev_data, gpio_cb); + + ARG_UNUSED(dev); + ARG_UNUSED(pins); + +#if defined(CONFIG_ICM4268X_TRIGGER_OWN_THREAD) + k_sem_give(&data->gpio_sem); +#elif defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif + if (IS_ENABLED(CONFIG_ICM4268X_STREAM)) { + icm4268x_fifo_event(data->dev); + } +} + +#if defined(CONFIG_ICM4268X_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) +static void icm4268x_thread_cb(const struct device *dev) +{ + struct icm4268x_dev_data *data = dev->data; + + icm4268x_lock(dev); + + if (data->data_ready_handler != NULL) { + data->data_ready_handler(dev, data->data_ready_trigger); + } + + icm4268x_unlock(dev); +} +#endif + +#ifdef CONFIG_ICM4268X_TRIGGER_OWN_THREAD + +static void icm4268x_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct icm4268x_dev_data *data = p1; + + while (1) { + k_sem_take(&data->gpio_sem, K_FOREVER); + icm4268x_thread_cb(data->dev); + } +} + +#elif defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) + +static void icm4268x_work_handler(struct k_work *work) +{ + struct icm4268x_dev_data *data = CONTAINER_OF(work, struct icm4268x_dev_data, work); + + icm4268x_thread_cb(data->dev); +} + +#endif + +int icm4268x_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct icm4268x_dev_data *data = dev->data; + const struct icm4268x_dev_cfg *cfg = dev->config; + uint8_t status; + int res = 0; + + if (trig == NULL || handler == NULL) { + return -EINVAL; + } + + icm4268x_lock(dev); + gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_DISABLE); + + switch (trig->type) { + case SENSOR_TRIG_DATA_READY: + case SENSOR_TRIG_FIFO_WATERMARK: + case SENSOR_TRIG_FIFO_FULL: + data->data_ready_handler = handler; + data->data_ready_trigger = trig; + + res = icm4268x_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); + break; + default: + res = -ENOTSUP; + break; + } + + icm4268x_unlock(dev); + gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + + return res; +} + +int icm4268x_trigger_init(const struct device *dev) +{ + struct icm4268x_dev_data *data = dev->data; + const struct icm4268x_dev_cfg *cfg = dev->config; + int res = 0; + + if (!cfg->gpio_int1.port) { + LOG_ERR("trigger enabled but no interrupt gpio supplied"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->gpio_int1)) { + LOG_ERR("gpio_int1 not ready"); + return -ENODEV; + } + + data->dev = dev; + gpio_pin_configure_dt(&cfg->gpio_int1, GPIO_INPUT); + gpio_init_callback(&data->gpio_cb, icm4268x_gpio_callback, BIT(cfg->gpio_int1.pin)); + res = gpio_add_callback(cfg->gpio_int1.port, &data->gpio_cb); + + if (res < 0) { + LOG_ERR("Failed to set gpio callback"); + return res; + } + + k_mutex_init(&data->mutex); +#if defined(CONFIG_ICM4268X_TRIGGER_OWN_THREAD) + k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT); + k_thread_create(&data->thread, data->thread_stack, CONFIG_ICM4268X_THREAD_STACK_SIZE, + icm4268x_thread, data, NULL, NULL, + K_PRIO_COOP(CONFIG_ICM4268X_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) + data->work.handler = icm4268x_work_handler; +#endif + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); +} + +int icm4268x_trigger_enable_interrupt(const struct device *dev, struct icm4268x_cfg *new_cfg) +{ + int res; + const struct icm4268x_dev_cfg *cfg = dev->config; + uint8_t int1_pol = (new_cfg->int1_pol ? BIT_INT1_POLARITY:0); + + /* Selected interrupt mode, push-pull and active-high */ + res = icm4268x_spi_single_write(&cfg->spi, REG_INT_CONFIG, + BIT_INT1_DRIVE_CIRCUIT | int1_pol + | (new_cfg->int1_mode ? BIT_INT1_MODE : 0)); + if (res != 0) { + return res; + } + + /* Deassert async reset for proper INT pin operation, see datasheet 14.50 */ + res = icm4268x_spi_single_write(&cfg->spi, REG_INT_CONFIG1, 0); + if (res != 0) { + return res; + } + + /* enable interrupts on INT1 pin */ + uint8_t value = 0; + + if (new_cfg->interrupt1_drdy) { + value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_ths) { + value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_full) { + value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1); + } + return icm4268x_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value); +} + +void icm4268x_lock(const struct device *dev) +{ + struct icm4268x_dev_data *data = dev->data; + + k_mutex_lock(&data->mutex, K_FOREVER); +} + +void icm4268x_unlock(const struct device *dev) +{ + struct icm4268x_dev_data *data = dev->data; + + k_mutex_unlock(&data->mutex); +} diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_trigger.h b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.h new file mode 100644 index 0000000000000..1eee4824b534a --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2023 Google LLC + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_TRIGGER_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_TRIGGER_H_ + +#include + +/** implement the trigger_set sensor api function */ +int icm4268x_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +/** + * @brief initialize the icm4268x trigger system + * + * @param dev icm4268x device pointer + * @return int 0 on success, negative error code otherwise + */ +int icm4268x_trigger_init(const struct device *dev); + +/** + * @brief enable the trigger gpio interrupt + * + * @param dev icm4268x device pointer + * @param new_cfg New configuration to use for the device + * @return int 0 on success, negative error code otherwise + */ +int icm4268x_trigger_enable_interrupt(const struct device *dev, struct icm4268x_cfg *new_cfg); + +/** + * @brief lock access to the icm4268x device driver + * + * @param dev icm4268x device pointer + */ +void icm4268x_lock(const struct device *dev); + +/** + * @brief lock access to the icm4268x device driver + * + * @param dev icm4268x device pointer + */ +void icm4268x_unlock(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_TRIGGER_H_ */ diff --git a/dts/bindings/sensor/invensense,icm42686.yaml b/dts/bindings/sensor/invensense,icm42686.yaml new file mode 100644 index 0000000000000..925fef5ffb188 --- /dev/null +++ b/dts/bindings/sensor/invensense,icm42686.yaml @@ -0,0 +1,71 @@ +# Copyright (c) 2024 Intel Corporation +# Copyright (c) 2022 Esco Medical ApS +# Copyright (c) 2020 TDK Invensense +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + ICM-42686 motion tracking device. + The properties included in this bindings file are the ones which + are different in different models. Common ones are in icm4268x.yaml. + When setting the accel-pwr-mode, accel-fs, accel-odr, gyro-pwr-mode, + gyro-fs, gyro-odr properties in a .dts or .dtsi file you may include + icm4268x.h and use the macros defined there. + + Example: + #include + + icm42686: icm42686@0 { + ... + + accel-pwr-mode = ; + accel-fs = ; + accel-odr = ; + gyro-pwr-mode= ; + gyro-fs = ; + gyro-odr = ; + }; + + Where, + ICM42686_DT_GYRO_FS_2000 represents +-2000 deg per sec + as the full scale range of the gyroscope. + + ICM42686_DT_ACCEL_FS_32 represents +-32 times g as the maximum + acceleration this device can measure. + +compatible: "invensense,icm42686" +include: invensense,icm4268x-common.yaml + +properties: + accel-fs: + type: int + default: 0 + description: | + Specify the accelerometer range in g. + Default accel full scale as recommended in manufacturer datasheet is 32g. + + 0 # ICM42686_DT_ACCEL_FS_32 + 1 # ICM42686_DT_ACCEL_FS_16 + 2 # ICM42686_DT_ACCEL_FS_8 + 3 # ICM42686_DT_ACCEL_FS_4 + 4 # ICM42686_DT_ACCEL_FS_2 + + enum: [0, 1, 2, 3, 4] + + gyro-fs: + type: int + default: 0 + description: | + Specify the gyro range in degrees per second. + Default gyro full scale as recommended in manufacturer datasheet is 4000 degrees per second. + + 0 # ICM42686_DT_GYRO_FS_4000 + 1 # ICM42686_DT_GYRO_FS_2000 + 2 # ICM42686_DT_GYRO_FS_1000 + 3 # ICM42686_DT_GYRO_FS_500 + 4 # ICM42686_DT_GYRO_FS_250 + 5 # ICM42686_DT_GYRO_FS_125 + 6 # ICM42686_DT_GYRO_FS_62_5 + 7 # ICM42686_DT_GYRO_FS_31_25 + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/invensense,icm42688.yaml b/dts/bindings/sensor/invensense,icm42688.yaml index c3c628e959720..fd64376249c91 100644 --- a/dts/bindings/sensor/invensense,icm42688.yaml +++ b/dts/bindings/sensor/invensense,icm42688.yaml @@ -4,124 +4,65 @@ # SPDX-License-Identifier: Apache-2.0 description: | - ICM-42688 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 icm42688.h - and use the macros defined there. + ICM-42688 motion tracking device. + The properties included in this bindings file are the ones which are + different in different device models. Common properties are included in + invensense,icm4268x.yaml. When setting properties in a .dts or .dtsi file + you may include icm4268x.h and use the macros defined there. Example: - #include + #include icm42688: icm42688@0 { ... - accel-pwr-mode = ; - accel-fs = ; - accel-odr = ; - gyro-pwr-mode= ; - gyro-fs = ; - gyro-odr = ; + accel-pwr-mode = ; + accel-fs = ; + accel-odr = ; + gyro-pwr-mode= ; + gyro-fs = ; + gyro-odr = ; }; -compatible: "invensense,icm42688" -include: [sensor-device.yaml, spi-device.yaml] -properties: - int-gpios: - type: phandle-array - description: | - The INT signal default configuration is active-high. The - property value should ensure the flags properly describe the - signal that is presented to the driver. + Where, + ICM42688_DT_GYRO_FS_2000 represents +-2000 deg per sec + as the full scale range of the gyroscope. - accel-pwr-mode: - type: int - default: 0 - description: | - Specify the default accelerometer power mode. - Default is power-up configuration. - enum: - - 0 # ICM42688_DT_ACCEL_OFF - - 2 # ICM42688_DT_ACCEL_LP - - 3 # ICM42688_DT_ACCEL_LN + ICM42688_DT_ACCEL_FS_16 represents +-16 times g as the maximum + acceleration this device can measure. - accel-odr: - type: int - default: 6 - description: | - Specify the default accelerometer output data rate expressed in samples per second (Hz). - Default is power-up configuration. - enum: - - 1 # ICM42688_DT_ACCEL_ODR_32000 - - 2 # ICM42688_DT_ACCEL_ODR_16000 - - 3 # ICM42688_DT_ACCEL_ODR_8000 - - 4 # ICM42688_DT_ACCEL_ODR_4000 - - 5 # ICM42688_DT_ACCEL_ODR_2000 - - 6 # ICM42688_DT_ACCEL_ODR_1000 - - 7 # ICM42688_DT_ACCEL_ODR_200 - - 8 # ICM42688_DT_ACCEL_ODR_100 - - 9 # ICM42688_DT_ACCEL_ODR_50 - - 10 # ICM42688_DT_ACCEL_ODR_25 - - 11 # ICM42688_DT_ACCEL_ODR_12_5 - - 12 # ICM42688_DT_ACCEL_ODR_6_25 - - 13 # ICM42688_DT_ACCEL_ODR_3_125 - - 14 # ICM42688_DT_ACCEL_ODR_1_5625 - - 15 # ICM42688_DT_ACCEL_ODR_500 +compatible: "invensense,icm42688" +include: invensense,icm4268x-common.yaml +properties: accel-fs: type: int default: 0 description: | Specify the accelerometer range in g. - Default is power-up configuration. - enum: - - 0 # ICM42688_DT_ACCEL_FS_16 - - 1 # ICM42688_DT_ACCEL_FS_8 - - 2 # ICM42688_DT_ACCEL_FS_4 - - 3 # ICM42688_DT_ACCEL_FS_2 + Default accel full scale as recommended in manufacturer datasheet is 16g. - gyro-pwr-mode: - type: int - default: 0 - description: | - Specify the default gyro power mode. - Default is power-up configuration. - enum: - - 0 # ICM42688_DT_GYRO_OFF - - 1 # ICM42688_DT_GYRO_STANDBY - - 3 # ICM42688_DT_GYRO_LN + 0 # ICM42688_DT_ACCEL_FS_16 + 1 # ICM42688_DT_ACCEL_FS_8 + 2 # ICM42688_DT_ACCEL_FS_4 + 3 # ICM42688_DT_ACCEL_FS_2 - gyro-odr: - type: int - default: 6 - description: | - Specify the default gyro output data rate expressed in samples per second (Hz). - Default is power-up configuration. - enum: - - 1 # ICM42688_DT_GYRO_ODR_32000 - - 2 # ICM42688_DT_GYRO_ODR_16000 - - 3 # ICM42688_DT_GYRO_ODR_8000 - - 4 # ICM42688_DT_GYRO_ODR_4000 - - 5 # ICM42688_DT_GYRO_ODR_2000 - - 6 # ICM42688_DT_GYRO_ODR_1000 - - 7 # ICM42688_DT_GYRO_ODR_200 - - 8 # ICM42688_DT_GYRO_ODR_100 - - 9 # ICM42688_DT_GYRO_ODR_50 - - 10 # ICM42688_DT_GYRO_ODR_25 - - 11 # ICM42688_DT_GYRO_ODR_12_5 - - 15 # ICM42688_DT_GYRO_ODR_500 + enum: [0, 1, 2, 3] gyro-fs: type: int default: 0 description: | Specify the gyro range in degrees per second. - Default is power-up configuration. - enum: - - 0 # ICM42688_DT_GYRO_FS_2000 - - 1 # ICM42688_DT_GYRO_FS_1000 - - 2 # ICM42688_DT_GYRO_FS_500 - - 3 # ICM42688_DT_GYRO_FS_250 - - 4 # ICM42688_DT_GYRO_FS_125 - - 5 # ICM42688_DT_GYRO_FS_62_5 - - 6 # ICM42688_DT_GYRO_FS_31_25 - - 7 # ICM42688_DT_GYRO_FS_15_625 + Default gyro full scale as recommended in manufacturer datasheet is 2000 degrees per second. + + 0 # ICM42688_DT_GYRO_FS_2000 + 1 # ICM42688_DT_GYRO_FS_1000 + 2 # ICM42688_DT_GYRO_FS_500 + 3 # ICM42688_DT_GYRO_FS_250 + 4 # ICM42688_DT_GYRO_FS_125 + 5 # ICM42688_DT_GYRO_FS_62_5 + 6 # ICM42688_DT_GYRO_FS_31_25 + 7 # ICM42688_DT_GYRO_FS_15_625 + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/invensense,icm4268x-common.yaml b/dts/bindings/sensor/invensense,icm4268x-common.yaml new file mode 100644 index 0000000000000..388a757df81d3 --- /dev/null +++ b/dts/bindings/sensor/invensense,icm4268x-common.yaml @@ -0,0 +1,369 @@ +# Copyright (c) 2024 Intel Corporation +# Copyright (c) 2022 Esco Medical ApS +# Copyright (c) 2020 TDK Invensense +# SPDX-License-Identifier: Apache-2.0 + +description: | + Generic bindings file for ICM-4268X models of motion tracking devices. + When setting the enum properties in a .dts or .dtsi file you may + include icm4268x.h and use the macros defined there. + + Example: + #include + + icm42688: icm42688@0 { + ... + + accel-pwr-mode = ; + accel-fs = ; + accel-odr = ; + gyro-pwr-mode= ; + gyro-fs = ; + gyro-odr = ; + accel-aaf-bw = ; + gyro-aaf-bw = ; + }; + + Where, + ICM4268X_DT_ACCEL_ODR_2000 represents 2kHz as rate of sample capture by the + accelerometer. + + ICM4268X_DT_GYRO_ODR_2000 represents 2kHz as rate of sample capture by the + gyroscope. + + ICM4268X_DT_ACCEL_AAF_42HZ represents 42kHz as the bandwidth of the + Anti Alias Filter for the Accelerometer device. + + ICM4268X_DT_GYRO_AAF_42HZ represents 42kHz as the bandwidth of the + Anti Alias Filter for the Gyroscope device. + +compatible: "invensense,icm4268x-common" +include: [sensor-device.yaml, spi-device.yaml] + +properties: + int-gpios: + type: phandle-array + description: | + This property describes the GPIO specification for INT line from ICM4268x package + on to your device. The property values should ensure the flags properly describe + the signal that is presented to the driver. + + int1-pol: + type: int + default: 0 + description: | + Choose if the interrupt1 polarity will be Active High or Ative Low. + Default polarity is active low. + + 0 # ICM4268X_DT_INT1_POLARITY_ACTIVE_LOW + 1 # ICM4268X_DT_INT1_POLARITY_ACTIVE_HIGH + + enum: [0, 1] + + int1-mode: + type: int + default: 0 + description: | + Choose if the interrupt will be automatically latched and then cleared (pulsed mode) + Or latch and clear happens only when user code requests the data (latched mode). + Default interrupt mode recommended by manufacturer datssheet is pulsed. + + 0 # ICM4268X_DT_INT1_MODE_PULSED + 1 # ICM4268X_DT_INT1_MODE_LATCHED + + enum: [0, 1] + + fifo-mode: + type: int + default: 0 + description: | + Select what to do when FIFO is full. Stream to FIFO mode will overwrite LRU frame. + Stop on Full mode will prevent writing any frame if both FIFO and cache are full. + Default fifo mode recommended by manufacturer datasheet is bypass. + + 0 # ICM4268X_DT_FIFO_MODE_BYPASS + 1 # ICM4268X_DT_FIFO_MODE_STREAM + 3 # ICM4268X_DT_FIFO_MODE_STOP_ON_FULL + + enum: [0, 1, 3] + + fifo-ths-int-clr: + type: int + default: 1 + description: | + Fifo threshold Interrupt Clearing Options. + Default fifo threshold interrupt (in latched mode) gets cleared on status bit read. + + 1 # ICM4268X_DT_FIFO_THS_INT_CLR_STSRD + 2 # ICM4268X_DT_FIFO_THS_INT_CLR_DATARD + 3 # ICM4268X_DT_FIFO_THS_INT_CLR_BOTH + + enum: [1, 2, 3] + + fifo-full-int-clr: + type: int + default: 1 + description: | + Fifo Full Interrupt Clearing Options. + Default fifo full interrupt (in latched mode) gets cleared on status bit read. + + 1 # ICM4268X_DT_FIFO_FULL_INT_CLR_STSRD + 2 # ICM4268X_DT_FIFO_FULL_INT_CLR_DATARD + 3 # ICM4268X_DT_FIFO_FULL_INT_CLR_BOTH + + enum: [1, 2, 3] + + tmst-dis: + type: boolean + description: | + Enable or disable the timestamp register. + Timestamp register is enabled by default. + + tmst-fsync-en: + type: boolean + description: | + Enable/disable timestamp fsync register. + Default timestamp feature of FSYNC is disabled. + + tmst-delta-en: + type: boolean + description: | + Timestamp register will have absolute or delta values from the last occurrence of ODR. + + tmst-res: + type: int + default: 0 + description: | + If 0, Timestamp Resolution is 1us, if 1 and RTC is enabled then time res is + RTC clock period else 16us. + Default timestamp resolution as per manufacturer datasheet is set to 1us. + + 0 # ICM4268X_DT_TMST_RES_1US + 1 # ICM4268X_DT_TMST_RES_RTC + + enum: [0, 1] + + tmst-regs-en: + type: boolean + description: | + If false, TMST_VALUE returns zeros else returns timestamp values. + + accel-pwr-mode: + type: int + default: 0 + description: | + Specify the accelerometer power mode. + Default power mode for accelerometer as recommended in manufacturer datasheet + is accelerometer off. + + 0 # ICM4268X_DT_ACCEL_OFF + 2 # ICM4268X_DT_ACCEL_LP + 3 # ICM4268X_DT_ACCEL_LN + + enum: [0, 2, 3] + + accel-odr: + type: int + default: 6 + description: | + Specify the accelerometer output data rate expressed in samples per second (Hz). + Default accelerometer ODR as recommended in manufacturer datasheet is 1kHz in Low Noise Mode. + + 1 # ICM4268X_DT_ACCEL_ODR_32000 + 2 # ICM4268X_DT_ACCEL_ODR_16000 + 3 # ICM4268X_DT_ACCEL_ODR_8000 + 4 # ICM4268X_DT_ACCEL_ODR_4000 + 5 # ICM4268X_DT_ACCEL_ODR_2000 + 6 # ICM4268X_DT_ACCEL_ODR_1000 + 7 # ICM4268X_DT_ACCEL_ODR_200 + 8 # ICM4268X_DT_ACCEL_ODR_100 + 9 # ICM4268X_DT_ACCEL_ODR_50 + 10 # ICM4268X_DT_ACCEL_ODR_25 + 11 # ICM4268X_DT_ACCEL_ODR_12_5 + 12 # ICM4268X_DT_ACCEL_ODR_6_25 + 13 # ICM4268X_DT_ACCEL_ODR_3_125 + 14 # ICM4268X_DT_ACCEL_ODR_1_5625 + 15 # ICM4268X_DT_ACCEL_ODR_500 + + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + + accel-aaf-bw: + type: int + description: | + Specify the Anti Aliasing Filter bandwidth for the accelerometer. + + 1 # ICM4268X_DT_ACCEL_AAF_42HZ + 2 # ICM4268X_DT_ACCEL_AAF_84HZ + 3 # ICM4268X_DT_ACCEL_AAF_126HZ + 4 # ICM4268X_DT_ACCEL_AAF_170HZ + 5 # ICM4268X_DT_ACCEL_AAF_213HZ + 6 # ICM4268X_DT_ACCEL_AAF_258HZ + 7 # ICM4268X_DT_ACCEL_AAF_303HZ + 8 # ICM4268X_DT_ACCEL_AAF_348HZ + 9 # ICM4268X_DT_ACCEL_AAF_394HZ + 10 # ICM4268X_DT_ACCEL_AAF_441HZ + 11 # ICM4268X_DT_ACCEL_AAF_488HZ + 12 # ICM4268X_DT_ACCEL_AAF_536HZ + 13 # ICM4268X_DT_ACCEL_AAF_585HZ + 14 # ICM4268X_DT_ACCEL_AAF_634HZ + 15 # ICM4268X_DT_ACCEL_AAF_684HZ + 16 # ICM4268X_DT_ACCEL_AAF_734HZ + 17 # ICM4268X_DT_ACCEL_AAF_785HZ + 18 # ICM4268X_DT_ACCEL_AAF_837HZ + 19 # ICM4268X_DT_ACCEL_AAF_890HZ + 20 # ICM4268X_DT_ACCEL_AAF_943HZ + 21 # ICM4268X_DT_ACCEL_AAF_997HZ + 22 # ICM4268X_DT_ACCEL_AAF_1051HZ + 23 # ICM4268X_DT_ACCEL_AAF_1107HZ + 24 # ICM4268X_DT_ACCEL_AAF_1163HZ + 25 # ICM4268X_DT_ACCEL_AAF_1220HZ + 26 # ICM4268X_DT_ACCEL_AAF_1277HZ + 27 # ICM4268X_DT_ACCEL_AAF_1336HZ + 28 # ICM4268X_DT_ACCEL_AAF_1395HZ + 29 # ICM4268X_DT_ACCEL_AAF_1454HZ + 30 # ICM4268X_DT_ACCEL_AAF_1515HZ + 31 # ICM4268X_DT_ACCEL_AAF_1577HZ + 32 # ICM4268X_DT_ACCEL_AAF_1639HZ + 33 # ICM4268X_DT_ACCEL_AAF_1702HZ + 34 # ICM4268X_DT_ACCEL_AAF_1766HZ + 35 # ICM4268X_DT_ACCEL_AAF_1830HZ + 36 # ICM4268X_DT_ACCEL_AAF_1896HZ + 37 # ICM4268X_DT_ACCEL_AAF_1962HZ + 38 # ICM4268X_DT_ACCEL_AAF_2029HZ + 39 # ICM4268X_DT_ACCEL_AAF_2097HZ + 40 # ICM4268X_DT_ACCEL_AAF_2166HZ + 41 # ICM4268X_DT_ACCEL_AAF_2235HZ + 42 # ICM4268X_DT_ACCEL_AAF_2306HZ + 43 # ICM4268X_DT_ACCEL_AAF_2377HZ + 44 # ICM4268X_DT_ACCEL_AAF_2449HZ + 45 # ICM4268X_DT_ACCEL_AAF_2522HZ + 46 # ICM4268X_DT_ACCEL_AAF_2596HZ + 47 # ICM4268X_DT_ACCEL_AAF_2671HZ + 48 # ICM4268X_DT_ACCEL_AAF_2746HZ + 49 # ICM4268X_DT_ACCEL_AAF_2823HZ + 50 # ICM4268X_DT_ACCEL_AAF_2900HZ + 51 # ICM4268X_DT_ACCEL_AAF_2978HZ + 52 # ICM4268X_DT_ACCEL_AAF_3057HZ + 53 # ICM4268X_DT_ACCEL_AAF_3137HZ + 54 # ICM4268X_DT_ACCEL_AAF_3217HZ + 55 # ICM4268X_DT_ACCEL_AAF_3299HZ + 56 # ICM4268X_DT_ACCEL_AAF_3381HZ + 57 # ICM4268X_DT_ACCEL_AAF_3464HZ + 58 # ICM4268X_DT_ACCEL_AAF_3548HZ + 59 # ICM4268X_DT_ACCEL_AAF_3633HZ + 60 # ICM4268X_DT_ACCEL_AAF_3718HZ + 61 # ICM4268X_DT_ACCEL_AAF_3805HZ + 62 # ICM4268X_DT_ACCEL_AAF_3892HZ + 63 # ICM4268X_DT_ACCEL_AAF_3979HZ + + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63] + + gyro-pwr-mode: + type: int + default: 0 + description: | + Specify the gyro power mode. + Default power mode for gyroscope as recommended in manufacturer datasheet is gyroscope off. + + 0 # ICM4268X_DT_GYRO_OFF + 1 # ICM4268X_DT_GYRO_STANDBY + 3 # ICM4268X_DT_GYRO_LN + + enum: [0, 1, 3] + + gyro-odr: + type: int + default: 6 + description: | + Specify the gyro output data rate expressed in samples per second (Hz). + Default gyroscope ODR as recommended in manufacturer datasheet is 1kHz. + + 1 # ICM4268X_DT_GYRO_ODR_32000 + 2 # ICM4268X_DT_GYRO_ODR_16000 + 3 # ICM4268X_DT_GYRO_ODR_8000 + 4 # ICM4268X_DT_GYRO_ODR_4000 + 5 # ICM4268X_DT_GYRO_ODR_2000 + 6 # ICM4268X_DT_GYRO_ODR_1000 + 7 # ICM4268X_DT_GYRO_ODR_200 + 8 # ICM4268X_DT_GYRO_ODR_100 + 9 # ICM4268X_DT_GYRO_ODR_50 + 10 # ICM4268X_DT_GYRO_ODR_25 + 11 # ICM4268X_DT_GYRO_ODR_12_5 + 15 # ICM4268X_DT_GYRO_ODR_500 + + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15] + + gyro-aaf-bw: + type: int + description: | + Specify the Anti Aliasing Filter bandwidth for the gyroscope. + + 1 # ICM4268X_DT_GYRO_AAF_42HZ + 2 # ICM4268X_DT_GYRO_AAF_84HZ + 3 # ICM4268X_DT_GYRO_AAF_126HZ + 4 # ICM4268X_DT_GYRO_AAF_170HZ + 5 # ICM4268X_DT_GYRO_AAF_213HZ + 6 # ICM4268X_DT_GYRO_AAF_258HZ + 7 # ICM4268X_DT_GYRO_AAF_303HZ + 8 # ICM4268X_DT_GYRO_AAF_348HZ + 9 # ICM4268X_DT_GYRO_AAF_394HZ + 10 # ICM4268X_DT_GYRO_AAF_441HZ + 11 # ICM4268X_DT_GYRO_AAF_488HZ + 12 # ICM4268X_DT_GYRO_AAF_536HZ + 13 # ICM4268X_DT_GYRO_AAF_585HZ + 14 # ICM4268X_DT_GYRO_AAF_634HZ + 15 # ICM4268X_DT_GYRO_AAF_684HZ + 16 # ICM4268X_DT_GYRO_AAF_734HZ + 17 # ICM4268X_DT_GYRO_AAF_785HZ + 18 # ICM4268X_DT_GYRO_AAF_837HZ + 19 # ICM4268X_DT_GYRO_AAF_890HZ + 20 # ICM4268X_DT_GYRO_AAF_943HZ + 21 # ICM4268X_DT_GYRO_AAF_997HZ + 22 # ICM4268X_DT_GYRO_AAF_1051HZ + 23 # ICM4268X_DT_GYRO_AAF_1107HZ + 24 # ICM4268X_DT_GYRO_AAF_1163HZ + 25 # ICM4268X_DT_GYRO_AAF_1220HZ + 26 # ICM4268X_DT_GYRO_AAF_1277HZ + 27 # ICM4268X_DT_GYRO_AAF_1336HZ + 28 # ICM4268X_DT_GYRO_AAF_1395HZ + 29 # ICM4268X_DT_GYRO_AAF_1454HZ + 30 # ICM4268X_DT_GYRO_AAF_1515HZ + 31 # ICM4268X_DT_GYRO_AAF_1577HZ + 32 # ICM4268X_DT_GYRO_AAF_1639HZ + 33 # ICM4268X_DT_GYRO_AAF_1702HZ + 34 # ICM4268X_DT_GYRO_AAF_1766HZ + 35 # ICM4268X_DT_GYRO_AAF_1830HZ + 36 # ICM4268X_DT_GYRO_AAF_1896HZ + 37 # ICM4268X_DT_GYRO_AAF_1962HZ + 38 # ICM4268X_DT_GYRO_AAF_2029HZ + 39 # ICM4268X_DT_GYRO_AAF_2097HZ + 40 # ICM4268X_DT_GYRO_AAF_2166HZ + 41 # ICM4268X_DT_GYRO_AAF_2235HZ + 42 # ICM4268X_DT_GYRO_AAF_2306HZ + 43 # ICM4268X_DT_GYRO_AAF_2377HZ + 44 # ICM4268X_DT_GYRO_AAF_2449HZ + 45 # ICM4268X_DT_GYRO_AAF_2522HZ + 46 # ICM4268X_DT_GYRO_AAF_2596HZ + 47 # ICM4268X_DT_GYRO_AAF_2671HZ + 48 # ICM4268X_DT_GYRO_AAF_2746HZ + 49 # ICM4268X_DT_GYRO_AAF_2823HZ + 50 # ICM4268X_DT_GYRO_AAF_2900HZ + 51 # ICM4268X_DT_GYRO_AAF_2978HZ + 52 # ICM4268X_DT_GYRO_AAF_3057HZ + 53 # ICM4268X_DT_GYRO_AAF_3137HZ + 54 # ICM4268X_DT_GYRO_AAF_3217HZ + 55 # ICM4268X_DT_GYRO_AAF_3299HZ + 56 # ICM4268X_DT_GYRO_AAF_3381HZ + 57 # ICM4268X_DT_GYRO_AAF_3464HZ + 58 # ICM4268X_DT_GYRO_AAF_3548HZ + 59 # ICM4268X_DT_GYRO_AAF_3633HZ + 60 # ICM4268X_DT_GYRO_AAF_3718HZ + 61 # ICM4268X_DT_GYRO_AAF_3805HZ + 62 # ICM4268X_DT_GYRO_AAF_3892HZ + 63 # ICM4268X_DT_GYRO_AAF_3979HZ + + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63] diff --git a/include/zephyr/dt-bindings/sensor/icm42688.h b/include/zephyr/dt-bindings/sensor/icm42688.h deleted file mode 100644 index 0eeb9f0984cb1..0000000000000 --- a/include/zephyr/dt-bindings/sensor/icm42688.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2024 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM42688P_H_ -#define ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM42688P_H_ - -/** - * @defgroup ICM42688 Invensense (TDK) ICM42688 DT Options - * @ingroup sensor_interface - * @{ - */ - -/** - * @defgroup ICM42688_ACCEL_POWER_MODES Accelerometer power modes - * @{ - */ -#define ICM42688_DT_ACCEL_OFF 0 -#define ICM42688_DT_ACCEL_LP 2 -#define ICM42688_DT_ACCEL_LN 3 -/** @} */ - -/** - * @defgroup ICM42688_GYRO_POWER_MODES Gyroscope power modes - * @{ - */ -#define ICM42688_DT_GYRO_OFF 0 -#define ICM42688_DT_GYRO_STANDBY 1 -#define ICM42688_DT_GYRO_LN 3 -/** @} */ - -/** - * @defgroup ICM42688_ACCEL_SCALE Accelerometer scale options - * @{ - */ -#define ICM42688_DT_ACCEL_FS_16 0 -#define ICM42688_DT_ACCEL_FS_8 1 -#define ICM42688_DT_ACCEL_FS_4 2 -#define ICM42688_DT_ACCEL_FS_2 3 -/** @} */ - -/** - * @defgroup ICM42688_GYRO_SCALE Gyroscope scale options - * @{ - */ -#define ICM42688_DT_GYRO_FS_2000 0 -#define ICM42688_DT_GYRO_FS_1000 1 -#define ICM42688_DT_GYRO_FS_500 2 -#define ICM42688_DT_GYRO_FS_250 3 -#define ICM42688_DT_GYRO_FS_125 4 -#define ICM42688_DT_GYRO_FS_62_5 5 -#define ICM42688_DT_GYRO_FS_31_25 6 -#define ICM42688_DT_GYRO_FS_15_625 7 -/** @} */ - -/** - * @defgroup ICM42688_ACCEL_DATA_RATE Accelerometer data rate options - * @{ - */ -#define ICM42688_DT_ACCEL_ODR_32000 1 -#define ICM42688_DT_ACCEL_ODR_16000 2 -#define ICM42688_DT_ACCEL_ODR_8000 3 -#define ICM42688_DT_ACCEL_ODR_4000 4 -#define ICM42688_DT_ACCEL_ODR_2000 5 -#define ICM42688_DT_ACCEL_ODR_1000 6 -#define ICM42688_DT_ACCEL_ODR_200 7 -#define ICM42688_DT_ACCEL_ODR_100 8 -#define ICM42688_DT_ACCEL_ODR_50 9 -#define ICM42688_DT_ACCEL_ODR_25 10 -#define ICM42688_DT_ACCEL_ODR_12_5 11 -#define ICM42688_DT_ACCEL_ODR_6_25 12 -#define ICM42688_DT_ACCEL_ODR_3_125 13 -#define ICM42688_DT_ACCEL_ODR_1_5625 14 -#define ICM42688_DT_ACCEL_ODR_500 15 -/** @} */ - -/** - * @defgroup ICM42688_GYRO_DATA_RATE Gyroscope data rate options - * @{ - */ -#define ICM42688_DT_GYRO_ODR_32000 1 -#define ICM42688_DT_GYRO_ODR_16000 2 -#define ICM42688_DT_GYRO_ODR_8000 3 -#define ICM42688_DT_GYRO_ODR_4000 4 -#define ICM42688_DT_GYRO_ODR_2000 5 -#define ICM42688_DT_GYRO_ODR_1000 6 -#define ICM42688_DT_GYRO_ODR_200 7 -#define ICM42688_DT_GYRO_ODR_100 8 -#define ICM42688_DT_GYRO_ODR_50 9 -#define ICM42688_DT_GYRO_ODR_25 10 -#define ICM42688_DT_GYRO_ODR_12_5 11 -#define ICM42688_DT_GYRO_ODR_500 15 -/** @} */ - -/** @} */ - -#endif /*ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM42688P_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/icm4268x.h b/include/zephyr/dt-bindings/sensor/icm4268x.h new file mode 100644 index 0000000000000..f9b986bb019a4 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/icm4268x.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2024 Intel Corporation + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM4268XP_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM4268XP_H_ + +/** + * @defgroup ICM4268X Invensense (TDK) ICM4268X DT Options + * @{ + */ + +/** + * @defgroup ICM4268X_FIFO_MODES Fifo Modes + * @{ + */ +#define ICM4268X_DT_FIFO_MODE_BYPASS 0 +#define ICM4268X_DT_FIFO_MODE_STREAM 1 +#define ICM4268X_DT_FIFO_MODE_STOP_ON_FULL 3 +/** @} */ + +/** + * @defgroup ICM4268X_INT_MODES Interrupt Modes + * @{ + */ +#define ICM4268X_DT_INT1_MODE_PULSED 0 +#define ICM4268X_DT_INT1_MODE_LATCHED 1 +/** @} */ + +/** + * @defgroup ICM4268X_INT_MODES Interrupt Modes + * @{ + */ +#define ICM4268X_DT_INT1_POLARITY_ACTIVE_LOW 0 +#define ICM4268X_DT_INT1_POLARITY_ACTIVE_HIGH 1 +/** @} */ + +/** + * @defgroup ICM4268X_INT_FIFO_THS_CLR FIFO Threshold Intterupt + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_FIFO_THS_INT_CLR_STSRD 1 +#define ICM4268X_DT_FIFO_THS_INT_CLR_DATARD 2 +#define ICM4268X_DT_FIFO_THS_INT_CLR_BOTH 3 +/** @} */ + +/** + * @defgroup ICM4268X_INT_FIFO_FULL_CLR FIFO Full Intterupt + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_FIFO_FULL_INT_CLR_STSRD 1 +#define ICM4268X_DT_FIFO_FULL_INT_CLR_DATARD 2 +#define ICM4268X_DT_FIFO_FULL_INT_CLR_BOTH 3 +/** @} */ + +/** + * @defgroup ICM4268X_TMST_EN Timestamp enable + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_TMST_DIS 0 +#define ICM4268X_DT_TMST_EN 1 +/** @} */ + +/** + * @defgroup ICM4268X_TMST_FSYNC_EN Timestamp fsync enable + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_TMST_FSYNC_DIS 0 +#define ICM4268X_DT_TMST_FSYNC_EN 1 +/** @} */ + +/** + * @defgroup ICM4268X_TMST_DELTA_EN Timestamp delta enable + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_TMST_DELTA_DIS 0 +#define ICM4268X_DT_TMST_DELTA_EN 1 +/** @} */ + +/** + * @defgroup ICM4268X_TMST_RES Timestamp resolution + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_TMST_RES_1US 0 +#define ICM4268X_DT_TMST_RES_RTC 1 +/** @} */ + +/** + * @defgroup ICM4268X_TMST_TO_REGS_EN Timestamp register + * Clearing conditions + * @{ + */ +#define ICM4268X_DT_TMST_REGS_DIS 0 +#define ICM4268X_DT_TMST_REGS_EN 1 +/** @} */ + +/** + * @defgroup ICM4268X_ACCEL_POWER_MODES Accelerometer power modes + * @{ + */ +#define ICM4268X_DT_ACCEL_OFF 0 +#define ICM4268X_DT_ACCEL_LP 2 +#define ICM4268X_DT_ACCEL_LN 3 +/** @} */ + +/** + * @defgroup ICM4268X_GYRO_POWER_MODES Gyroscope power modes + * @{ + */ +#define ICM4268X_DT_GYRO_OFF 0 +#define ICM4268X_DT_GYRO_STANDBY 1 +#define ICM4268X_DT_GYRO_LN 3 +/** @} */ + +/** + * @defgroup ICM42686_ACCEL_SCALE Accelerometer scale options + * @{ + */ +#define ICM42686_DT_ACCEL_FS_32 0 +#define ICM42686_DT_ACCEL_FS_16 1 +#define ICM42686_DT_ACCEL_FS_8 2 +#define ICM42686_DT_ACCEL_FS_4 3 +#define ICM42686_DT_ACCEL_FS_2 4 +/** @} */ + +/** + * @defgroup ICM42688_ACCEL_SCALE Accelerometer scale options + * @{ + */ +#define ICM42688_DT_ACCEL_FS_16 0 +#define ICM42688_DT_ACCEL_FS_8 1 +#define ICM42688_DT_ACCEL_FS_4 2 +#define ICM42688_DT_ACCEL_FS_2 3 +/** @} */ + +/** + * @defgroup ICM42686_GYRO_SCALE Gyroscope scale options + * @{ + */ +#define ICM42686_DT_GYRO_FS_4000 0 +#define ICM42686_DT_GYRO_FS_2000 1 +#define ICM42686_DT_GYRO_FS_1000 2 +#define ICM42686_DT_GYRO_FS_500 3 +#define ICM42686_DT_GYRO_FS_250 4 +#define ICM42686_DT_GYRO_FS_125 5 +#define ICM42686_DT_GYRO_FS_62_5 6 +#define ICM42686_DT_GYRO_FS_31_25 7 +/** @} */ + +/** + * @defgroup ICM42688_GYRO_SCALE Gyroscope scale options + * @{ + */ +#define ICM42688_DT_GYRO_FS_2000 0 +#define ICM42688_DT_GYRO_FS_1000 1 +#define ICM42688_DT_GYRO_FS_500 2 +#define ICM42688_DT_GYRO_FS_250 3 +#define ICM42688_DT_GYRO_FS_125 4 +#define ICM42688_DT_GYRO_FS_62_5 5 +#define ICM42688_DT_GYRO_FS_31_25 6 +#define ICM42688_DT_GYRO_FS_15_625 7 +/** @} */ + +/** + * @defgroup ICM4268X_ACCEL_DATA_RATE Accelerometer data rate options + * @{ + */ +#define ICM4268X_DT_ACCEL_ODR_32000 1 +#define ICM4268X_DT_ACCEL_ODR_16000 2 +#define ICM4268X_DT_ACCEL_ODR_8000 3 +#define ICM4268X_DT_ACCEL_ODR_4000 4 +#define ICM4268X_DT_ACCEL_ODR_2000 5 +#define ICM4268X_DT_ACCEL_ODR_1000 6 +#define ICM4268X_DT_ACCEL_ODR_200 7 +#define ICM4268X_DT_ACCEL_ODR_100 8 +#define ICM4268X_DT_ACCEL_ODR_50 9 +#define ICM4268X_DT_ACCEL_ODR_25 10 +#define ICM4268X_DT_ACCEL_ODR_12_5 11 +#define ICM4268X_DT_ACCEL_ODR_6_25 12 +#define ICM4268X_DT_ACCEL_ODR_3_125 13 +#define ICM4268X_DT_ACCEL_ODR_1_5625 14 +#define ICM4268X_DT_ACCEL_ODR_500 15 +/** @} */ + +/** + * @defgroup ICM4268X_GYRO_DATA_RATE Gyroscope data rate options + * @{ + */ +#define ICM4268X_DT_GYRO_ODR_32000 1 +#define ICM4268X_DT_GYRO_ODR_16000 2 +#define ICM4268X_DT_GYRO_ODR_8000 3 +#define ICM4268X_DT_GYRO_ODR_4000 4 +#define ICM4268X_DT_GYRO_ODR_2000 5 +#define ICM4268X_DT_GYRO_ODR_1000 6 +#define ICM4268X_DT_GYRO_ODR_200 7 +#define ICM4268X_DT_GYRO_ODR_100 8 +#define ICM4268X_DT_GYRO_ODR_50 9 +#define ICM4268X_DT_GYRO_ODR_25 10 +#define ICM4268X_DT_GYRO_ODR_12_5 11 +#define ICM4268X_DT_GYRO_ODR_500 15 +/** @} */ + +/** + * @defgroup ICM4268X_ACCEL_AAF_BW Accelerometer Anti Aliasing Filter Bandwidth options + * @{ + */ +#define ICM4268X_DT_ACCEL_AAF_42HZ 1 +#define ICM4268X_DT_ACCEL_AAF_84HZ 2 +#define ICM4268X_DT_ACCEL_AAF_126HZ 3 +#define ICM4268X_DT_ACCEL_AAF_170HZ 4 +#define ICM4268X_DT_ACCEL_AAF_213HZ 5 +#define ICM4268X_DT_ACCEL_AAF_258HZ 6 +#define ICM4268X_DT_ACCEL_AAF_303HZ 7 +#define ICM4268X_DT_ACCEL_AAF_348HZ 8 +#define ICM4268X_DT_ACCEL_AAF_394HZ 9 +#define ICM4268X_DT_ACCEL_AAF_441HZ 10 +#define ICM4268X_DT_ACCEL_AAF_488HZ 11 +#define ICM4268X_DT_ACCEL_AAF_536HZ 12 +#define ICM4268X_DT_ACCEL_AAF_585HZ 13 +#define ICM4268X_DT_ACCEL_AAF_634HZ 14 +#define ICM4268X_DT_ACCEL_AAF_684HZ 15 +#define ICM4268X_DT_ACCEL_AAF_734HZ 16 +#define ICM4268X_DT_ACCEL_AAF_785HZ 17 +#define ICM4268X_DT_ACCEL_AAF_837HZ 18 +#define ICM4268X_DT_ACCEL_AAF_890HZ 19 +#define ICM4268X_DT_ACCEL_AAF_943HZ 20 +#define ICM4268X_DT_ACCEL_AAF_997HZ 21 +#define ICM4268X_DT_ACCEL_AAF_1051HZ 22 +#define ICM4268X_DT_ACCEL_AAF_1107HZ 23 +#define ICM4268X_DT_ACCEL_AAF_1163HZ 24 +#define ICM4268X_DT_ACCEL_AAF_1220HZ 25 +#define ICM4268X_DT_ACCEL_AAF_1277HZ 26 +#define ICM4268X_DT_ACCEL_AAF_1336HZ 27 +#define ICM4268X_DT_ACCEL_AAF_1395HZ 28 +#define ICM4268X_DT_ACCEL_AAF_1454HZ 29 +#define ICM4268X_DT_ACCEL_AAF_1515HZ 30 +#define ICM4268X_DT_ACCEL_AAF_1577HZ 31 +#define ICM4268X_DT_ACCEL_AAF_1639HZ 32 +#define ICM4268X_DT_ACCEL_AAF_1702HZ 33 +#define ICM4268X_DT_ACCEL_AAF_1766HZ 34 +#define ICM4268X_DT_ACCEL_AAF_1830HZ 35 +#define ICM4268X_DT_ACCEL_AAF_1896HZ 36 +#define ICM4268X_DT_ACCEL_AAF_1962HZ 37 +#define ICM4268X_DT_ACCEL_AAF_2029HZ 38 +#define ICM4268X_DT_ACCEL_AAF_2097HZ 39 +#define ICM4268X_DT_ACCEL_AAF_2166HZ 40 +#define ICM4268X_DT_ACCEL_AAF_2235HZ 41 +#define ICM4268X_DT_ACCEL_AAF_2306HZ 42 +#define ICM4268X_DT_ACCEL_AAF_2377HZ 43 +#define ICM4268X_DT_ACCEL_AAF_2449HZ 44 +#define ICM4268X_DT_ACCEL_AAF_2522HZ 45 +#define ICM4268X_DT_ACCEL_AAF_2596HZ 46 +#define ICM4268X_DT_ACCEL_AAF_2671HZ 47 +#define ICM4268X_DT_ACCEL_AAF_2746HZ 48 +#define ICM4268X_DT_ACCEL_AAF_2823HZ 49 +#define ICM4268X_DT_ACCEL_AAF_2900HZ 50 +#define ICM4268X_DT_ACCEL_AAF_2978HZ 51 +#define ICM4268X_DT_ACCEL_AAF_3057HZ 52 +#define ICM4268X_DT_ACCEL_AAF_3137HZ 53 +#define ICM4268X_DT_ACCEL_AAF_3217HZ 54 +#define ICM4268X_DT_ACCEL_AAF_3299HZ 55 +#define ICM4268X_DT_ACCEL_AAF_3381HZ 56 +#define ICM4268X_DT_ACCEL_AAF_3464HZ 57 +#define ICM4268X_DT_ACCEL_AAF_3548HZ 58 +#define ICM4268X_DT_ACCEL_AAF_3633HZ 59 +#define ICM4268X_DT_ACCEL_AAF_3718HZ 60 +#define ICM4268X_DT_ACCEL_AAF_3805HZ 61 +#define ICM4268X_DT_ACCEL_AAF_3892HZ 62 +#define ICM4268X_DT_ACCEL_AAF_3979HZ 63 +/** @} */ + +/** + * @defgroup ICM4268X_GYRO_AAF_BW Gyroscope Anti Aliasing Filter Bandwidth options + * @{ + */ +#define ICM4268X_DT_GYRO_AAF_42HZ 1 +#define ICM4268X_DT_GYRO_AAF_84HZ 2 +#define ICM4268X_DT_GYRO_AAF_126HZ 3 +#define ICM4268X_DT_GYRO_AAF_170HZ 4 +#define ICM4268X_DT_GYRO_AAF_213HZ 5 +#define ICM4268X_DT_GYRO_AAF_258HZ 6 +#define ICM4268X_DT_GYRO_AAF_303HZ 7 +#define ICM4268X_DT_GYRO_AAF_348HZ 8 +#define ICM4268X_DT_GYRO_AAF_394HZ 9 +#define ICM4268X_DT_GYRO_AAF_441HZ 10 +#define ICM4268X_DT_GYRO_AAF_488HZ 11 +#define ICM4268X_DT_GYRO_AAF_536HZ 12 +#define ICM4268X_DT_GYRO_AAF_585HZ 13 +#define ICM4268X_DT_GYRO_AAF_634HZ 14 +#define ICM4268X_DT_GYRO_AAF_684HZ 15 +#define ICM4268X_DT_GYRO_AAF_734HZ 16 +#define ICM4268X_DT_GYRO_AAF_785HZ 17 +#define ICM4268X_DT_GYRO_AAF_837HZ 18 +#define ICM4268X_DT_GYRO_AAF_890HZ 19 +#define ICM4268X_DT_GYRO_AAF_943HZ 20 +#define ICM4268X_DT_GYRO_AAF_997HZ 21 +#define ICM4268X_DT_GYRO_AAF_1051HZ 22 +#define ICM4268X_DT_GYRO_AAF_1107HZ 23 +#define ICM4268X_DT_GYRO_AAF_1163HZ 24 +#define ICM4268X_DT_GYRO_AAF_1220HZ 25 +#define ICM4268X_DT_GYRO_AAF_1277HZ 26 +#define ICM4268X_DT_GYRO_AAF_1336HZ 27 +#define ICM4268X_DT_GYRO_AAF_1395HZ 28 +#define ICM4268X_DT_GYRO_AAF_1454HZ 29 +#define ICM4268X_DT_GYRO_AAF_1515HZ 30 +#define ICM4268X_DT_GYRO_AAF_1577HZ 31 +#define ICM4268X_DT_GYRO_AAF_1639HZ 32 +#define ICM4268X_DT_GYRO_AAF_1702HZ 33 +#define ICM4268X_DT_GYRO_AAF_1766HZ 34 +#define ICM4268X_DT_GYRO_AAF_1830HZ 35 +#define ICM4268X_DT_GYRO_AAF_1896HZ 36 +#define ICM4268X_DT_GYRO_AAF_1962HZ 37 +#define ICM4268X_DT_GYRO_AAF_2029HZ 38 +#define ICM4268X_DT_GYRO_AAF_2097HZ 39 +#define ICM4268X_DT_GYRO_AAF_2166HZ 40 +#define ICM4268X_DT_GYRO_AAF_2235HZ 41 +#define ICM4268X_DT_GYRO_AAF_2306HZ 42 +#define ICM4268X_DT_GYRO_AAF_2377HZ 43 +#define ICM4268X_DT_GYRO_AAF_2449HZ 44 +#define ICM4268X_DT_GYRO_AAF_2522HZ 45 +#define ICM4268X_DT_GYRO_AAF_2596HZ 46 +#define ICM4268X_DT_GYRO_AAF_2671HZ 47 +#define ICM4268X_DT_GYRO_AAF_2746HZ 48 +#define ICM4268X_DT_GYRO_AAF_2823HZ 49 +#define ICM4268X_DT_GYRO_AAF_2900HZ 50 +#define ICM4268X_DT_GYRO_AAF_2978HZ 51 +#define ICM4268X_DT_GYRO_AAF_3057HZ 52 +#define ICM4268X_DT_GYRO_AAF_3137HZ 53 +#define ICM4268X_DT_GYRO_AAF_3217HZ 54 +#define ICM4268X_DT_GYRO_AAF_3299HZ 55 +#define ICM4268X_DT_GYRO_AAF_3381HZ 56 +#define ICM4268X_DT_GYRO_AAF_3464HZ 57 +#define ICM4268X_DT_GYRO_AAF_3548HZ 58 +#define ICM4268X_DT_GYRO_AAF_3633HZ 59 +#define ICM4268X_DT_GYRO_AAF_3718HZ 60 +#define ICM4268X_DT_GYRO_AAF_3805HZ 61 +#define ICM4268X_DT_GYRO_AAF_3892HZ 62 +#define ICM4268X_DT_GYRO_AAF_3979HZ 63 +/** @} */ + +/** @} */ +#endif /*ZEPHYR_INCLUDE_DT_BINDINGS_TDK_ICM4268XP_H_ */ diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index ebfa224848a32..0b1a225300ed1 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -138,7 +138,8 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, <&test_gpio 0 0>, - <&test_gpio 0 0>; /* 0x2e */ + <&test_gpio 0 0>, + <&test_gpio 0 0>; /* 0x2f */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 3a36a350e6a88..b780decb8ba7f 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -25,7 +25,7 @@ CONFIG_HMC5883L_TRIGGER_GLOBAL_THREAD=y CONFIG_HTS221_TRIGGER_GLOBAL_THREAD=y CONFIG_ICM42605_TRIGGER_GLOBAL_THREAD=y CONFIG_ICM42670_TRIGGER_GLOBAL_THREAD=y -CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD=y +CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD=y CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD=y CONFIG_IIS2DLPC_TRIGGER_GLOBAL_THREAD=y CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 805347a11a787..a7f6d3458e5e4 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -25,7 +25,7 @@ CONFIG_HMC5883L_TRIGGER_NONE=y CONFIG_HTS221_TRIGGER_NONE=y CONFIG_ICM42605_TRIGGER_NONE=y CONFIG_ICM42670_TRIGGER_NONE=y -CONFIG_ICM42688_TRIGGER_NONE=y +CONFIG_ICM4268X_TRIGGER_NONE=y CONFIG_IIS2DH_TRIGGER_NONE=y CONFIG_IIS2DLPC_TRIGGER_NONE=y CONFIG_IIS2ICLX_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index ef31101c3c19b..df0696535079f 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -23,7 +23,7 @@ CONFIG_GROW_R502A_TRIGGER_OWN_THREAD=y CONFIG_HMC5883L_TRIGGER_OWN_THREAD=y CONFIG_HTS221_TRIGGER_OWN_THREAD=y CONFIG_ICM42670_TRIGGER_OWN_THREAD=y -CONFIG_ICM42688_TRIGGER_OWN_THREAD=y +CONFIG_ICM4268X_TRIGGER_OWN_THREAD=y CONFIG_IIS2DH_TRIGGER_OWN_THREAD=y CONFIG_IIS2DLPC_TRIGGER_OWN_THREAD=y CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index c173c5ccecb61..6f6ffbd6b7ec6 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -198,6 +198,8 @@ test_spi_bme680: bme680@19 { test_spi_icm426888: icm42688@1a { compatible = "invensense,icm42688"; reg = <0x1a>; + accel-aaf-bw = <13>; + gyro-aaf-bw = <13>; spi-max-frequency = <24000000>; }; @@ -379,3 +381,11 @@ test_spi_tle9104: tle9104@2e { #sensor-cells = <0>; }; }; + +test_spi_icm42686: icm42686@2f { + compatible = "invensense,icm42686"; + reg = <0x2f>; + accel-aaf-bw = <13>; + gyro-aaf-bw = <13>; + spi-max-frequency = <24000000>; +}; diff --git a/tests/drivers/sensor/icm42688/boards/native_sim.overlay b/tests/drivers/sensor/icm42688/boards/native_sim.overlay deleted file mode 100644 index 9247b6365bb27..0000000000000 --- a/tests/drivers/sensor/icm42688/boards/native_sim.overlay +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -&spi0 { - icm42688: icm42688@3 { - compatible = "invensense,icm42688"; - int-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; - spi-max-frequency = <50000000>; - reg = <3>; - }; -}; diff --git a/tests/drivers/sensor/icm42688/src/main.c b/tests/drivers/sensor/icm42688/src/main.c deleted file mode 100644 index a4d314dd08a4d..0000000000000 --- a/tests/drivers/sensor/icm42688/src/main.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "icm42688_emul.h" -#include "icm42688_reg.h" - -#define NODE DT_NODELABEL(icm42688) - -DEFINE_FFF_GLOBALS; - -struct icm42688_fixture { - const struct device *dev; - const struct emul *target; -}; - -static void *icm42688_setup(void) -{ - static struct icm42688_fixture fixture = { - .dev = DEVICE_DT_GET(DT_NODELABEL(icm42688)), - .target = EMUL_DT_GET(DT_NODELABEL(icm42688)), - }; - - zassert_not_null(fixture.dev); - zassert_not_null(fixture.target); - return &fixture; -} - -ZTEST_SUITE(icm42688, NULL, icm42688_setup, NULL, NULL, NULL); - -ZTEST_F(icm42688, test_fetch_fail_no_ready_data) -{ - uint8_t status = 0; - - icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, &status, 1); - zassert_equal(-EBUSY, sensor_sample_fetch(fixture->dev)); -} - -static void test_fetch_temp_mc(const struct icm42688_fixture *fixture, int16_t temperature_mc) -{ - struct sensor_value value; - int64_t expected_uc; - int64_t actual_uc; - int16_t temperature_reg; - uint8_t buffer[2]; - - /* Set the INT_STATUS register to show we have data */ - buffer[0] = BIT_INT_STATUS_DATA_RDY; - icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, buffer, 1); - - /* - * Set the temperature data to 22.5C via: - * reg_val / 132.48 + 25 - */ - temperature_reg = ((temperature_mc - 25000) * 13248) / 100000; - buffer[0] = (temperature_reg >> 8) & GENMASK(7, 0); - buffer[1] = temperature_reg & GENMASK(7, 0); - icm42688_emul_set_reg(fixture->target, REG_TEMP_DATA1, buffer, 2); - - /* Fetch the data */ - zassert_ok(sensor_sample_fetch(fixture->dev)); - zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &value)); - - /* Assert data is within 5 milli-C of the tested temperature */ - expected_uc = temperature_mc * INT64_C(1000); - actual_uc = sensor_value_to_micro(&value); - zassert_within(expected_uc, actual_uc, INT64_C(5000), - "Expected %" PRIi64 "uC, got %" PRIi64 "uC", expected_uc, actual_uc); -} - -ZTEST_F(icm42688, test_fetch_temp) -{ - /* Test 22.5C */ - test_fetch_temp_mc(fixture, 22500); - /* Test -3.175C */ - test_fetch_temp_mc(fixture, -3175); -} - -static void test_fetch_accel_with_range(const struct icm42688_fixture *fixture, - int16_t accel_range_g, const int16_t accel_percent[3]) -{ - struct sensor_value values[3]; - int32_t expect_ug; - int32_t actual_ug; - uint8_t register_buffer[6]; - - /* Se the INT_STATUS register to show we have data */ - register_buffer[0] = BIT_INT_STATUS_DATA_RDY; - icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); - - /* Set accel range */ - sensor_g_to_ms2(accel_range_g, &values[0]); - zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, - &values[0])); - - /* Set the accel data accel_percent * accel_range_g */ - for (int i = 0; i < 3; ++i) { - register_buffer[i * 2] = (accel_percent[i] >> 8) & GENMASK(7, 0); - register_buffer[i * 2 + 1] = accel_percent[i] & GENMASK(7, 0); - } - icm42688_emul_set_reg(fixture->target, REG_ACCEL_DATA_X1, register_buffer, 6); - - /* Fetch the data */ - zassert_ok(sensor_sample_fetch(fixture->dev)); - zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, values)); - - /* Assert the data is within 0.005g (0.05m/s2) */ - actual_ug = sensor_ms2_to_ug(&values[0]); - expect_ug = (int32_t)(accel_percent[0] * INT64_C(1000000) * accel_range_g / INT16_MAX); - zassert_within(expect_ug, actual_ug, INT32_C(5000), - "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); - - actual_ug = sensor_ms2_to_ug(&values[1]); - expect_ug = (int32_t)(accel_percent[1] * INT64_C(1000000) * accel_range_g / INT16_MAX); - zassert_within(expect_ug, actual_ug, INT32_C(5000), - "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); - - actual_ug = sensor_ms2_to_ug(&values[2]); - expect_ug = (int32_t)(accel_percent[2] * INT64_C(1000000) * accel_range_g / INT16_MAX); - zassert_within(expect_ug, actual_ug, INT32_C(5000), - "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); -} - -ZTEST_F(icm42688, test_fetch_accel) -{ - /* Use (0.25, -0.33.., 0.91) * range for testing accel values */ - const int16_t accel_percent[3] = { - INT16_MAX / INT16_C(4), - INT16_MIN / INT16_C(3), - (int16_t)((INT16_MAX * INT32_C(91)) / INT32_C(100)), - }; - - test_fetch_accel_with_range(fixture, 2, accel_percent); - test_fetch_accel_with_range(fixture, 4, accel_percent); - test_fetch_accel_with_range(fixture, 8, accel_percent); - test_fetch_accel_with_range(fixture, 16, accel_percent); -} - -static void test_fetch_gyro_with_range(const struct icm42688_fixture *fixture, int32_t scale_mdps, - const int16_t gyro_percent[3]) -{ - /* Set the epsilon to 0.075% of the scale */ - const int32_t epsilon_10udps = scale_mdps * 75 / 1000; - struct sensor_value values[3]; - int32_t expect_10udps; - int32_t actual_10udps; - uint8_t register_buffer[6]; - - /* Se the INT_STATUS register to show we have data */ - register_buffer[0] = BIT_INT_STATUS_DATA_RDY; - icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); - - /* Set gyro range */ - sensor_degrees_to_rad((scale_mdps / 1000) + (scale_mdps % 1000 == 0 ? 0 : 1), &values[0]); - zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, - &values[0])); - - /* Set the gyro data to gyro_percent */ - for (int i = 0; i < 3; ++i) { - register_buffer[i * 2] = (gyro_percent[i] >> 8) & GENMASK(7, 0); - register_buffer[i * 2 + 1] = gyro_percent[i] & GENMASK(7, 0); - } - icm42688_emul_set_reg(fixture->target, REG_GYRO_DATA_X1, register_buffer, 6); - - /* Fetch the data */ - zassert_ok(sensor_sample_fetch(fixture->dev)); - zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_GYRO_XYZ, values)); - - /* Assert the data is within 0.5 d/s (0.001 rad/s) */ - actual_10udps = sensor_rad_to_10udegrees(&values[0]); - expect_10udps = (int32_t)(gyro_percent[0] * INT64_C(100) * scale_mdps / INT16_MAX); - zassert_within(expect_10udps, actual_10udps, epsilon_10udps, - "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 - " 10ud/s", - scale_mdps, expect_10udps, actual_10udps); - - actual_10udps = sensor_rad_to_10udegrees(&values[1]); - expect_10udps = (int32_t)(gyro_percent[1] * INT64_C(100) * scale_mdps / INT16_MAX); - zassert_within(expect_10udps, actual_10udps, epsilon_10udps, - "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 - " 10ud/s, ", - scale_mdps, expect_10udps, actual_10udps); - - actual_10udps = sensor_rad_to_10udegrees(&values[2]); - expect_10udps = (int32_t)(gyro_percent[2] * INT64_C(100) * scale_mdps / INT16_MAX); - zassert_within(expect_10udps, actual_10udps, epsilon_10udps, - "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 - " 10ud/s", - scale_mdps, expect_10udps, actual_10udps); -} - -ZTEST_F(icm42688, test_fetch_gyro) -{ - /* Use (0.15, 0.68, -0.22) * range for testing gyro values */ - const int16_t gyro_percent[3] = { - (int16_t)((INT16_MAX * INT32_C(15)) / INT32_C(100)), - (int16_t)((INT16_MAX * INT32_C(68)) / INT32_C(100)), - (int16_t)((INT16_MAX * INT32_C(-22)) / INT32_C(100)), - }; - - test_fetch_gyro_with_range(fixture, 2000000, gyro_percent); - test_fetch_gyro_with_range(fixture, 1000000, gyro_percent); - test_fetch_gyro_with_range(fixture, 500000, gyro_percent); - test_fetch_gyro_with_range(fixture, 250000, gyro_percent); - test_fetch_gyro_with_range(fixture, 125000, gyro_percent); - test_fetch_gyro_with_range(fixture, 62500, gyro_percent); - test_fetch_gyro_with_range(fixture, 31250, gyro_percent); - test_fetch_gyro_with_range(fixture, 15625, gyro_percent); -} - -FAKE_VOID_FUNC(test_interrupt_trigger_handler, const struct device*, const struct sensor_trigger*); - -ZTEST_F(icm42688, test_interrupt) -{ - const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(NODE, int_gpios); - const struct sensor_trigger trigger = { - .type = SENSOR_TRIG_DATA_READY, - .chan = SENSOR_CHAN_ALL, - }; - - RESET_FAKE(test_interrupt_trigger_handler); - sensor_trigger_set(fixture->dev, &trigger, test_interrupt_trigger_handler); - - /* Toggle the GPIO */ - gpio_emul_input_set(spec.port, spec.pin, 0); - k_msleep(5); - gpio_emul_input_set(spec.port, spec.pin, 1); - k_msleep(5); - - /* Verify the handler was called */ - zassert_equal(test_interrupt_trigger_handler_fake.call_count, 1); -} diff --git a/tests/drivers/sensor/icm42688/CMakeLists.txt b/tests/drivers/sensor/icm4268x/CMakeLists.txt similarity index 100% rename from tests/drivers/sensor/icm42688/CMakeLists.txt rename to tests/drivers/sensor/icm4268x/CMakeLists.txt diff --git a/tests/drivers/sensor/icm4268x/boards/native_sim.overlay b/tests/drivers/sensor/icm4268x/boards/native_sim.overlay new file mode 100644 index 0000000000000..17da5e131155b --- /dev/null +++ b/tests/drivers/sensor/icm4268x/boards/native_sim.overlay @@ -0,0 +1,25 @@ +/* Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&spi0 { + icm42686: icm42686@2 { + compatible = "invensense,icm42686"; + int-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + spi-max-frequency = <50000000>; + reg = <2>; + accel-aaf-bw = ; + gyro-aaf-bw = ; + }; + + icm42688: icm42688@3 { + compatible = "invensense,icm42688"; + int-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + spi-max-frequency = <50000000>; + reg = <3>; + accel-aaf-bw = ; + gyro-aaf-bw = ; + }; +}; diff --git a/tests/drivers/sensor/icm42688/prj.conf b/tests/drivers/sensor/icm4268x/prj.conf similarity index 100% rename from tests/drivers/sensor/icm42688/prj.conf rename to tests/drivers/sensor/icm4268x/prj.conf diff --git a/tests/drivers/sensor/icm4268x/src/main.c b/tests/drivers/sensor/icm4268x/src/main.c new file mode 100644 index 0000000000000..b7db2cd9ae3e4 --- /dev/null +++ b/tests/drivers/sensor/icm4268x/src/main.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icm4268x_emul.h" +#include "icm4268x_reg.h" + +#define NODE1 DT_NODELABEL(icm42686) +#define NODE2 DT_NODELABEL(icm42688) + +DEFINE_FFF_GLOBALS; + +struct icm42686_fixture { + const struct device *dev; + const struct emul *target; +}; + +struct icm42688_fixture { + const struct device *dev; + const struct emul *target; +}; + +static void *icm42686_setup(void) +{ + static struct icm42686_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(icm42686)), + .target = EMUL_DT_GET(DT_NODELABEL(icm42686)), + }; + + zassert_not_null(fixture.dev); + zassert_not_null(fixture.target); + return &fixture; +} + +static void *icm42688_setup(void) +{ + static struct icm42688_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(icm42688)), + .target = EMUL_DT_GET(DT_NODELABEL(icm42688)), + }; + + zassert_not_null(fixture.dev); + zassert_not_null(fixture.target); + return &fixture; +} + +ZTEST_SUITE(icm42686, NULL, icm42686_setup, NULL, NULL, NULL); + +ZTEST_F(icm42686, test_fetch_fail_no_ready_data) +{ + uint8_t status = 0; + + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, &status, 1); + zassert_equal(-EBUSY, sensor_sample_fetch(fixture->dev)); +} + +ZTEST_SUITE(icm42688, NULL, icm42688_setup, NULL, NULL, NULL); + +ZTEST_F(icm42688, test_fetch_fail_no_ready_data) +{ + uint8_t status = 0; + + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, &status, 1); + zassert_equal(-EBUSY, sensor_sample_fetch(fixture->dev)); +} + +static void test_fetch_temp_mc_icm42686(const struct icm42686_fixture *fixture, + int16_t temperature_mc) +{ + struct sensor_value value; + int64_t expected_uc; + int64_t actual_uc; + int16_t temperature_reg; + uint8_t buffer[2]; + + /* Set the INT_STATUS register to show we have data */ + buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, buffer, 1); + + /* + * Set the temperature data to 22.5C via: + * reg_val / 132.48 + 25 + */ + temperature_reg = ((temperature_mc - 25000) * 13248) / 100000; + buffer[0] = (temperature_reg >> 8) & GENMASK(7, 0); + buffer[1] = temperature_reg & GENMASK(7, 0); + icm4268x_emul_set_reg(fixture->target, REG_TEMP_DATA1, buffer, 2); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &value)); + + /* Assert data is within 5 milli-C of the tested temperature */ + expected_uc = temperature_mc * INT64_C(1000); + actual_uc = sensor_value_to_micro(&value); + zassert_within(expected_uc, actual_uc, INT64_C(5000), + "Expected %" PRIi64 "uC, got %" PRIi64 "uC", expected_uc, actual_uc); +} + +static void test_fetch_temp_mc_icm42688(const struct icm42688_fixture *fixture, + int16_t temperature_mc) +{ + struct sensor_value value; + int64_t expected_uc; + int64_t actual_uc; + int16_t temperature_reg; + uint8_t buffer[2]; + + /* Set the INT_STATUS register to show we have data */ + buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, buffer, 1); + + /* + * Set the temperature data to 22.5C via: + * reg_val / 132.48 + 25 + */ + temperature_reg = ((temperature_mc - 25000) * 13248) / 100000; + buffer[0] = (temperature_reg >> 8) & GENMASK(7, 0); + buffer[1] = temperature_reg & GENMASK(7, 0); + icm4268x_emul_set_reg(fixture->target, REG_TEMP_DATA1, buffer, 2); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &value)); + + /* Assert data is within 5 milli-C of the tested temperature */ + expected_uc = temperature_mc * INT64_C(1000); + actual_uc = sensor_value_to_micro(&value); + zassert_within(expected_uc, actual_uc, INT64_C(5000), + "Expected %" PRIi64 "uC, got %" PRIi64 "uC", expected_uc, actual_uc); +} + +ZTEST_F(icm42686, test_fetch_temp) +{ + /* Test 22.5C */ + test_fetch_temp_mc_icm42686(fixture, 22500); + /* Test -3.175C */ + test_fetch_temp_mc_icm42686(fixture, -3175); +} + +ZTEST_F(icm42688, test_fetch_temp) +{ + /* Test 22.5C */ + test_fetch_temp_mc_icm42688(fixture, 22500); + /* Test -3.175C */ + test_fetch_temp_mc_icm42688(fixture, -3175); +} + +static void test_fetch_accel_with_range_icm42686(const struct icm42686_fixture *fixture, + int16_t accel_range_g, const int16_t accel_percent[3]) +{ + struct sensor_value values[3]; + int32_t expect_ug; + int32_t actual_ug; + uint8_t register_buffer[6]; + + /* Se the INT_STATUS register to show we have data */ + register_buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); + + /* Set accel range */ + sensor_g_to_ms2(accel_range_g, &values[0]); + zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, + &values[0])); + + /* Set the accel data accel_percent * accel_range_g */ + for (int i = 0; i < 3; ++i) { + register_buffer[i * 2] = (accel_percent[i] >> 8) & GENMASK(7, 0); + register_buffer[i * 2 + 1] = accel_percent[i] & GENMASK(7, 0); + } + icm4268x_emul_set_reg(fixture->target, REG_ACCEL_DATA_X1, register_buffer, 6); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, values)); + + /* Assert the data is within 0.005g (0.05m/s2) */ + actual_ug = sensor_ms2_to_ug(&values[0]); + expect_ug = (int32_t)(accel_percent[0] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); + + actual_ug = sensor_ms2_to_ug(&values[1]); + expect_ug = (int32_t)(accel_percent[1] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); + + actual_ug = sensor_ms2_to_ug(&values[2]); + expect_ug = (int32_t)(accel_percent[2] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); +} + +static void test_fetch_accel_with_range_icm42688(const struct icm42688_fixture *fixture, + int16_t accel_range_g, const int16_t accel_percent[3]) +{ + struct sensor_value values[3]; + int32_t expect_ug; + int32_t actual_ug; + uint8_t register_buffer[6]; + + /* Se the INT_STATUS register to show we have data */ + register_buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); + + /* Set accel range */ + sensor_g_to_ms2(accel_range_g, &values[0]); + zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, + &values[0])); + + /* Set the accel data accel_percent * accel_range_g */ + for (int i = 0; i < 3; ++i) { + register_buffer[i * 2] = (accel_percent[i] >> 8) & GENMASK(7, 0); + register_buffer[i * 2 + 1] = accel_percent[i] & GENMASK(7, 0); + } + icm4268x_emul_set_reg(fixture->target, REG_ACCEL_DATA_X1, register_buffer, 6); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, values)); + + /* Assert the data is within 0.005g (0.05m/s2) */ + actual_ug = sensor_ms2_to_ug(&values[0]); + expect_ug = (int32_t)(accel_percent[0] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); + + actual_ug = sensor_ms2_to_ug(&values[1]); + expect_ug = (int32_t)(accel_percent[1] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); + + actual_ug = sensor_ms2_to_ug(&values[2]); + expect_ug = (int32_t)(accel_percent[2] * INT64_C(1000000) * accel_range_g / INT16_MAX); + zassert_within(expect_ug, actual_ug, INT32_C(5000), + "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug); +} + +ZTEST_F(icm42686, test_fetch_accel) +{ + /* Use (0.25, -0.33.., 0.91) * range for testing accel values */ + const int16_t accel_percent[3] = { + INT16_MAX / INT16_C(4), + INT16_MIN / INT16_C(3), + (int16_t)((INT16_MAX * INT32_C(91)) / INT32_C(100)), + }; + + test_fetch_accel_with_range_icm42686(fixture, 2, accel_percent); + test_fetch_accel_with_range_icm42686(fixture, 4, accel_percent); + test_fetch_accel_with_range_icm42686(fixture, 8, accel_percent); + test_fetch_accel_with_range_icm42686(fixture, 16, accel_percent); + test_fetch_accel_with_range_icm42686(fixture, 32, accel_percent); +} + +ZTEST_F(icm42688, test_fetch_accel) +{ + /* Use (0.25, -0.33.., 0.91) * range for testing accel values */ + const int16_t accel_percent[3] = { + INT16_MAX / INT16_C(4), + INT16_MIN / INT16_C(3), + (int16_t)((INT16_MAX * INT32_C(91)) / INT32_C(100)), + }; + + test_fetch_accel_with_range_icm42688(fixture, 2, accel_percent); + test_fetch_accel_with_range_icm42688(fixture, 4, accel_percent); + test_fetch_accel_with_range_icm42688(fixture, 8, accel_percent); + test_fetch_accel_with_range_icm42688(fixture, 16, accel_percent); +} + +static void test_fetch_gyro_with_range_icm42686(const struct icm42686_fixture *fixture, + int32_t scale_mdps, const int16_t gyro_percent[3]) +{ + /* Set the epsilon to 0.075% of the scale */ + const int32_t epsilon_10udps = scale_mdps * 75 / 1000; + struct sensor_value values[3]; + int32_t expect_10udps; + int32_t actual_10udps; + uint8_t register_buffer[6]; + + /* Se the INT_STATUS register to show we have data */ + register_buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); + + /* Set gyro range */ + sensor_degrees_to_rad((scale_mdps / 1000) + (scale_mdps % 1000 == 0 ? 0 : 1), &values[0]); + zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, + &values[0])); + + /* Set the gyro data to gyro_percent */ + for (int i = 0; i < 3; ++i) { + register_buffer[i * 2] = (gyro_percent[i] >> 8) & GENMASK(7, 0); + register_buffer[i * 2 + 1] = gyro_percent[i] & GENMASK(7, 0); + } + icm4268x_emul_set_reg(fixture->target, REG_GYRO_DATA_X1, register_buffer, 6); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_GYRO_XYZ, values)); + + /* Assert the data is within 0.5 d/s (0.001 rad/s) */ + actual_10udps = sensor_rad_to_10udegrees(&values[0]); + expect_10udps = (int32_t)(gyro_percent[0] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s", + scale_mdps, expect_10udps, actual_10udps); + + actual_10udps = sensor_rad_to_10udegrees(&values[1]); + expect_10udps = (int32_t)(gyro_percent[1] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s, ", + scale_mdps, expect_10udps, actual_10udps); + + actual_10udps = sensor_rad_to_10udegrees(&values[2]); + expect_10udps = (int32_t)(gyro_percent[2] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s", + scale_mdps, expect_10udps, actual_10udps); +} + +static void test_fetch_gyro_with_range_icm42688(const struct icm42688_fixture *fixture, + int32_t scale_mdps, const int16_t gyro_percent[3]) +{ + /* Set the epsilon to 0.075% of the scale */ + const int32_t epsilon_10udps = scale_mdps * 75 / 1000; + struct sensor_value values[3]; + int32_t expect_10udps; + int32_t actual_10udps; + uint8_t register_buffer[6]; + + /* Se the INT_STATUS register to show we have data */ + register_buffer[0] = BIT_INT_STATUS_DATA_RDY; + icm4268x_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1); + + /* Set gyro range */ + sensor_degrees_to_rad((scale_mdps / 1000) + (scale_mdps % 1000 == 0 ? 0 : 1), &values[0]); + zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, + &values[0])); + + /* Set the gyro data to gyro_percent */ + for (int i = 0; i < 3; ++i) { + register_buffer[i * 2] = (gyro_percent[i] >> 8) & GENMASK(7, 0); + register_buffer[i * 2 + 1] = gyro_percent[i] & GENMASK(7, 0); + } + icm4268x_emul_set_reg(fixture->target, REG_GYRO_DATA_X1, register_buffer, 6); + + /* Fetch the data */ + zassert_ok(sensor_sample_fetch(fixture->dev)); + zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_GYRO_XYZ, values)); + + /* Assert the data is within 0.5 d/s (0.001 rad/s) */ + actual_10udps = sensor_rad_to_10udegrees(&values[0]); + expect_10udps = (int32_t)(gyro_percent[0] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s", + scale_mdps, expect_10udps, actual_10udps); + + actual_10udps = sensor_rad_to_10udegrees(&values[1]); + expect_10udps = (int32_t)(gyro_percent[1] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s, ", + scale_mdps, expect_10udps, actual_10udps); + + actual_10udps = sensor_rad_to_10udegrees(&values[2]); + expect_10udps = (int32_t)(gyro_percent[2] * INT64_C(100) * scale_mdps / INT16_MAX); + zassert_within(expect_10udps, actual_10udps, epsilon_10udps, + "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32 + " 10ud/s", + scale_mdps, expect_10udps, actual_10udps); +} + +ZTEST_F(icm42686, test_fetch_gyro) +{ + /* Use (0.15, 0.68, -0.22) * range for testing gyro values */ + const int16_t gyro_percent[3] = { + (int16_t)((INT16_MAX * INT32_C(15)) / INT32_C(100)), + (int16_t)((INT16_MAX * INT32_C(68)) / INT32_C(100)), + (int16_t)((INT16_MAX * INT32_C(-22)) / INT32_C(100)), + }; + + test_fetch_gyro_with_range_icm42686(fixture, 4000000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 2000000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 1000000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 500000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 250000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 125000, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 62500, gyro_percent); + test_fetch_gyro_with_range_icm42686(fixture, 31250, gyro_percent); +} + +ZTEST_F(icm42688, test_fetch_gyro) +{ + /* Use (0.15, 0.68, -0.22) * range for testing gyro values */ + const int16_t gyro_percent[3] = { + (int16_t)((INT16_MAX * INT32_C(15)) / INT32_C(100)), + (int16_t)((INT16_MAX * INT32_C(68)) / INT32_C(100)), + (int16_t)((INT16_MAX * INT32_C(-22)) / INT32_C(100)), + }; + + test_fetch_gyro_with_range_icm42688(fixture, 2000000, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 1000000, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 500000, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 250000, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 125000, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 62500, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 31250, gyro_percent); + test_fetch_gyro_with_range_icm42688(fixture, 15625, gyro_percent); +} + +FAKE_VOID_FUNC(test_interrupt_trigger_handler, const struct device*, const struct sensor_trigger*); + +ZTEST_F(icm42686, test_interrupt) +{ + const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(NODE1, int_gpios); + const struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + + RESET_FAKE(test_interrupt_trigger_handler); + sensor_trigger_set(fixture->dev, &trigger, test_interrupt_trigger_handler); + + /* Toggle the GPIO */ + gpio_emul_input_set(spec.port, spec.pin, 0); + k_msleep(5); + gpio_emul_input_set(spec.port, spec.pin, 1); + k_msleep(5); + + /* Verify the handler was called */ + zassert_equal(test_interrupt_trigger_handler_fake.call_count, 1); +} + +ZTEST_F(icm42688, test_interrupt) +{ + const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(NODE2, int_gpios); + const struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + + RESET_FAKE(test_interrupt_trigger_handler); + sensor_trigger_set(fixture->dev, &trigger, test_interrupt_trigger_handler); + + /* Toggle the GPIO */ + gpio_emul_input_set(spec.port, spec.pin, 0); + k_msleep(5); + gpio_emul_input_set(spec.port, spec.pin, 1); + k_msleep(5); + + /* Verify the handler was called */ + zassert_equal(test_interrupt_trigger_handler_fake.call_count, 1); +} diff --git a/tests/drivers/sensor/icm42688/testcase.yaml b/tests/drivers/sensor/icm4268x/testcase.yaml similarity index 86% rename from tests/drivers/sensor/icm42688/testcase.yaml rename to tests/drivers/sensor/icm4268x/testcase.yaml index 6f886cb6191df..37089fe1bdac8 100644 --- a/tests/drivers/sensor/icm42688/testcase.yaml +++ b/tests/drivers/sensor/icm4268x/testcase.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 tests: - drivers.sensor.icm42688: + drivers.sensor.icm4268x: tags: - drivers - sensor