| /* |
| * Copyright (c) 2022 Intel Corporation |
| * Copyright (c) 2025 Croxel Inc. |
| * Copyright (c) 2025 CogniPilot Foundation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_DRIVERS_SENSOR_ICM45686_H_ |
| #define ZEPHYR_DRIVERS_SENSOR_ICM45686_H_ |
| |
| #include <stdint.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/dt-bindings/sensor/icm45686.h> |
| #include <zephyr/rtio/rtio.h> |
| |
| struct icm45686_encoded_payload { |
| union { |
| uint8_t buf[14]; |
| int16_t readings[7]; |
| struct { |
| struct { |
| int16_t x; |
| int16_t y; |
| int16_t z; |
| } accel; |
| struct { |
| int16_t x; |
| int16_t y; |
| int16_t z; |
| } gyro; |
| int16_t temp; |
| } __attribute__((__packed__)); |
| }; |
| }; |
| |
| struct icm45686_encoded_fifo_payload { |
| union { |
| uint8_t buf[20]; |
| struct { |
| uint8_t header; |
| struct { |
| int16_t x; |
| int16_t y; |
| int16_t z; |
| } accel; |
| struct { |
| int16_t x; |
| int16_t y; |
| int16_t z; |
| } gyro; |
| int16_t temp; |
| uint16_t timestamp; |
| struct { |
| uint8_t gyro_x : 4; |
| uint8_t accel_x : 4; |
| uint8_t gyro_y : 4; |
| uint8_t accel_y : 4; |
| uint8_t gyro_z : 4; |
| uint8_t accel_z : 4; |
| } lsb; |
| } __attribute__((__packed__)); |
| }; |
| }; |
| |
| struct icm45686_encoded_header { |
| uint64_t timestamp; |
| uint8_t accel_fs : 4; |
| uint8_t gyro_fs : 4; |
| uint8_t events : 3; |
| uint8_t channels : 7; |
| uint16_t fifo_count; |
| }; |
| |
| struct icm45686_encoded_data { |
| struct icm45686_encoded_header header; |
| union { |
| struct icm45686_encoded_payload payload; |
| struct icm45686_encoded_fifo_payload fifo_payload; |
| }; |
| }; |
| |
| struct icm45686_triggers { |
| struct gpio_callback cb; |
| const struct device *dev; |
| struct k_mutex lock; |
| struct { |
| struct sensor_trigger trigger; |
| sensor_trigger_handler_t handler; |
| } entry; |
| #if defined(CONFIG_ICM45686_TRIGGER_OWN_THREAD) |
| K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ICM45686_THREAD_STACK_SIZE); |
| struct k_thread thread; |
| struct k_sem sem; |
| #elif defined(CONFIG_ICM45686_TRIGGER_GLOBAL_THREAD) |
| struct k_work work; |
| #endif |
| }; |
| |
| struct icm45686_stream { |
| struct gpio_callback cb; |
| const struct device *dev; |
| struct rtio_iodev_sqe *iodev_sqe; |
| atomic_t in_progress; |
| struct { |
| struct { |
| bool drdy : 1; |
| bool fifo_ths : 1; |
| bool fifo_full : 1; |
| } enabled; |
| struct { |
| enum sensor_stream_data_opt drdy; |
| enum sensor_stream_data_opt fifo_ths; |
| enum sensor_stream_data_opt fifo_full; |
| } opt; |
| bool drdy : 1; |
| bool fifo_ths : 1; |
| bool fifo_full : 1; |
| } settings; |
| struct { |
| uint64_t timestamp; |
| uint8_t int_status; |
| uint16_t fifo_count; |
| struct { |
| bool drdy : 1; |
| bool fifo_ths : 1; |
| bool fifo_full : 1; |
| } events; |
| } data; |
| }; |
| |
| struct icm45686_data { |
| struct { |
| struct rtio_iodev *iodev; |
| struct rtio *ctx; |
| } rtio; |
| /** Single-shot encoded data instance to support fetch/get API */ |
| struct icm45686_encoded_data edata; |
| #if defined(CONFIG_ICM45686_TRIGGER) |
| struct icm45686_triggers triggers; |
| #elif defined(CONFIG_ICM45686_STREAM) |
| struct icm45686_stream stream; |
| #endif /* CONFIG_ICM45686_TRIGGER */ |
| }; |
| |
| struct icm45686_config { |
| struct { |
| struct { |
| uint8_t pwr_mode : 2; |
| uint8_t fs : 4; |
| uint8_t odr : 4; |
| uint8_t lpf : 3; |
| } accel; |
| struct { |
| uint8_t pwr_mode : 2; |
| uint8_t fs : 4; |
| uint8_t odr : 4; |
| uint8_t lpf : 3; |
| } gyro; |
| uint16_t fifo_watermark; |
| } settings; |
| struct gpio_dt_spec int_gpio; |
| }; |
| |
| static inline void icm45686_accel_ms(uint8_t fs, |
| int32_t in, |
| bool high_res, |
| int32_t *out_ms, |
| int32_t *out_ums) |
| { |
| int64_t sensitivity; |
| uint64_t full_scale_range_lsb = high_res ? 524288 : 32768; |
| |
| switch (fs) { |
| case ICM45686_DT_ACCEL_FS_32: |
| sensitivity = full_scale_range_lsb / 32; |
| break; |
| case ICM45686_DT_ACCEL_FS_16: |
| sensitivity = full_scale_range_lsb / 16; |
| break; |
| case ICM45686_DT_ACCEL_FS_8: |
| sensitivity = full_scale_range_lsb / 8; |
| break; |
| case ICM45686_DT_ACCEL_FS_4: |
| sensitivity = full_scale_range_lsb / 4; |
| break; |
| case ICM45686_DT_ACCEL_FS_2: |
| sensitivity = full_scale_range_lsb / 2; |
| break; |
| default: |
| CODE_UNREACHABLE; |
| } |
| |
| /* 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; |
| } |
| |
| static inline void icm45686_gyro_rads(uint8_t fs, |
| int32_t in, |
| bool high_res, |
| int32_t *out_rads, |
| int32_t *out_urads) |
| { |
| int64_t sensitivity_x10; |
| uint64_t full_scale_range_lsb = high_res ? 524288 : 32768; |
| |
| switch (fs) { |
| case ICM45686_DT_GYRO_FS_4000: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 4000; |
| break; |
| case ICM45686_DT_GYRO_FS_2000: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 2000; |
| break; |
| case ICM45686_DT_GYRO_FS_1000: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 1000; |
| break; |
| case ICM45686_DT_GYRO_FS_500: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 500; |
| break; |
| case ICM45686_DT_GYRO_FS_250: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 250; |
| break; |
| case ICM45686_DT_GYRO_FS_125: |
| sensitivity_x10 = full_scale_range_lsb * 10 / 125; |
| break; |
| case ICM45686_DT_GYRO_FS_62_5: |
| sensitivity_x10 = full_scale_range_lsb * 10 * 10 / 625; |
| break; |
| case ICM45686_DT_GYRO_FS_31_25: |
| sensitivity_x10 = full_scale_range_lsb * 10 * 100 / 3125; |
| break; |
| case ICM45686_DT_GYRO_FS_15_625: |
| sensitivity_x10 = full_scale_range_lsb * 10 * 1000 / 15625; |
| break; |
| default: |
| CODE_UNREACHABLE; |
| } |
| |
| int64_t in10_rads = (int64_t)in * SENSOR_PI * 10LL; |
| |
| /* Whole rad/s */ |
| *out_rads = in10_rads / (sensitivity_x10 * 180LL * 1000000LL); |
| |
| /* microrad/s */ |
| *out_urads = (in10_rads - (*out_rads * sensitivity_x10 * 180LL * 1000000LL)) / |
| (sensitivity_x10 * 180LL); |
| } |
| |
| static inline void icm45686_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_ICM45686_H_ */ |