drivers: sensor: Add icm40627 6-axis accelerometer driver

Initial driver for the icm40627 from Invensense/TDK, a 6-axis
accelerometer with gyroscope and temperature sensing capabilities.

Signed-off-by: Florijan Plohl <florijan.plohl@norik.com>
This commit is contained in:
Florijan Plohl 2024-12-16 12:53:16 +01:00 committed by Benjamin Cabé
commit e0bd460de0
12 changed files with 1471 additions and 0 deletions

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
# zephyr-keep-sorted-start
add_subdirectory_ifdef(CONFIG_ICM40627 icm40627)
add_subdirectory_ifdef(CONFIG_ICM42605 icm42605)
add_subdirectory_ifdef(CONFIG_ICM42688 icm42688)
add_subdirectory_ifdef(CONFIG_ICM42X70 icm42x70)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
# zephyr-keep-sorted-start
source "drivers/sensor/tdk/icm40627/Kconfig"
source "drivers/sensor/tdk/icm42605/Kconfig"
source "drivers/sensor/tdk/icm42688/Kconfig"
source "drivers/sensor/tdk/icm42x70/Kconfig"

View file

@ -0,0 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(
icm40627.c
icm40627_i2c.c
)
zephyr_library_sources_ifdef(CONFIG_ICM40627_TRIGGER icm40627_trigger.c)

View file

@ -0,0 +1,22 @@
# ICM40627 Six-Axis Motion Tracking device configuration options
#
# Copyright (c) 2025 PHYTEC America LLC
#
# SPDX-License-Identifier: Apache-2.0
menuconfig ICM40627
bool "ICM40627 Six-Axis Motion Tracking Device"
default y
depends on DT_HAS_INVENSENSE_ICM40627_ENABLED
select I2C
help
Enable driver for ICM40627 I2C-based six-axis motion tracking device.
if ICM40627
module = ICM40627
thread_priority = 10
thread_stack_size = 1024
source "drivers/sensor/Kconfig.trigger_template"
endif # ICM40627

View file

@ -0,0 +1,708 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT invensense_icm40627
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/byteorder.h>
#include "icm40627.h"
#include "icm40627_reg.h"
#include "icm40627_trigger.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(ICM40627, CONFIG_SENSOR_LOG_LEVEL);
/*
* Gyro FS to scaling factor mapping.
* See datasheet section 3.1 for details
*/
static const uint16_t icm40627_gyro_sensitivity_x10[] = {
[BIT_GYRO_UI_FS_2000] 164, [BIT_GYRO_UI_FS_1000] 328, [BIT_GYRO_UI_FS_500] 655,
[BIT_GYRO_UI_FS_250] 1310, [BIT_GYRO_UI_FS_125] 2620, [BIT_GYRO_UI_FS_62] 5243,
[BIT_GYRO_UI_FS_31] 10486, [BIT_GYRO_UI_FS_15] 20972,
};
static int icm40627_set_accel_fs(const struct device *dev, uint16_t fs)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
struct sensor_value accel_fs_value;
uint8_t temp, round_fs;
if ((fs > 16) || (fs < 2)) {
LOG_ERR("Unsupported accel fs range");
return -ENOTSUP;
}
if (fs > 8) {
temp = BIT_ACCEL_UI_FS_16;
round_fs = 16;
} else if (fs > 4) {
temp = BIT_ACCEL_UI_FS_8;
round_fs = 8;
} else if (fs > 2) {
temp = BIT_ACCEL_UI_FS_4;
round_fs = 4;
} else {
temp = BIT_ACCEL_UI_FS_2;
round_fs = 2;
}
sensor_g_to_ms2(round_fs, &accel_fs_value);
data->accel_fs = accel_fs_value.val1;
data->accel_sensitivity_shift = MIN_ACCEL_SENS_SHIFT;
return cfg->bus_io->update(&cfg->bus, REG_ACCEL_CONFIG0, (uint8_t)MASK_ACCEL_UI_FS_SEL,
temp);
}
static int icm40627_set_gyro_fs(const struct device *dev, uint16_t fs)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
struct sensor_value gyro_fs_value;
uint8_t temp;
uint16_t round_fs;
if ((fs > 2000) || (fs < 15)) {
LOG_ERR("Unsupported gyro fs range");
return -ENOTSUP;
}
if (fs > 1000) {
temp = BIT_GYRO_UI_FS_2000;
round_fs = 2000;
} else if (fs > 500) {
temp = BIT_GYRO_UI_FS_1000;
round_fs = 1000;
} else if (fs > 250) {
temp = BIT_GYRO_UI_FS_500;
round_fs = 500;
} else if (fs > 125) {
temp = BIT_GYRO_UI_FS_250;
round_fs = 250;
} else if (fs > 62) {
temp = BIT_GYRO_UI_FS_125;
round_fs = 125;
} else if (fs > 31) {
temp = BIT_GYRO_UI_FS_62;
round_fs = 62;
} else if (fs > 15) {
temp = BIT_GYRO_UI_FS_31;
round_fs = 31;
} else {
temp = BIT_GYRO_UI_FS_15;
round_fs = 15;
}
sensor_degrees_to_rad(round_fs, &gyro_fs_value);
data->gyro_fs = gyro_fs_value.val1;
data->gyro_sensitivity_x10 = icm40627_gyro_sensitivity_x10[temp];
return cfg->bus_io->update(&cfg->bus, REG_GYRO_CONFIG0, (uint8_t)MASK_GYRO_UI_FS_SEL, temp);
}
static int icm40627_set_accel_odr(const struct device *dev, uint16_t rate)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
uint8_t temp;
uint16_t round_rate;
if ((rate > 8000) || (rate < 1)) {
LOG_ERR("Unsupported accel odr frequency");
return -ENOTSUP;
}
if (rate > 4000) {
temp = BIT_ACCEL_ODR_8000;
round_rate = 8000;
} else if (rate > 2000) {
temp = BIT_ACCEL_ODR_4000;
round_rate = 4000;
} else if (rate > 1000) {
temp = BIT_ACCEL_ODR_2000;
round_rate = 2000;
} else if (rate > 500) {
temp = BIT_ACCEL_ODR_1000;
round_rate = 1000;
} else if (rate > 200) {
temp = BIT_ACCEL_ODR_500;
round_rate = 500;
} else if (rate > 100) {
temp = BIT_ACCEL_ODR_200;
round_rate = 200;
} else if (rate > 50) {
temp = BIT_ACCEL_ODR_100;
round_rate = 100;
} else if (rate > 25) {
temp = BIT_ACCEL_ODR_50;
round_rate = 50;
} else if (rate > 12) {
temp = BIT_ACCEL_ODR_25;
round_rate = 25;
} else if (rate > 6) {
temp = BIT_ACCEL_ODR_12;
round_rate = 12;
} else if (rate > 3) {
temp = BIT_ACCEL_ODR_6;
round_rate = 6;
} else if (rate > 1) {
temp = BIT_ACCEL_ODR_3;
round_rate = 3;
} else {
temp = BIT_ACCEL_ODR_1;
round_rate = 1;
}
data->accel_hz = round_rate;
return cfg->bus_io->update(&cfg->bus, REG_ACCEL_CONFIG0, (uint8_t)MASK_ACCEL_ODR, temp);
}
static int icm40627_set_gyro_odr(const struct device *dev, uint16_t rate)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
uint8_t temp;
uint16_t round_rate;
if ((rate > 8000) || (rate < 12)) {
LOG_ERR("Unsupported gyro odr frequency");
return -ENOTSUP;
}
if (rate > 4000) {
temp = BIT_GYRO_ODR_8000;
round_rate = 8000;
} else if (rate > 2000) {
temp = BIT_GYRO_ODR_4000;
round_rate = 4000;
} else if (rate > 1000) {
temp = BIT_GYRO_ODR_2000;
round_rate = 2000;
} else if (rate > 500) {
temp = BIT_GYRO_ODR_1000;
round_rate = 1000;
} else if (rate > 200) {
temp = BIT_GYRO_ODR_500;
round_rate = 500;
} else if (rate > 100) {
temp = BIT_GYRO_ODR_200;
round_rate = 200;
} else if (rate > 50) {
temp = BIT_GYRO_ODR_100;
round_rate = 100;
} else if (rate > 25) {
temp = BIT_GYRO_ODR_50;
round_rate = 50;
} else if (rate > 12) {
temp = BIT_GYRO_ODR_25;
round_rate = 25;
} else {
temp = BIT_GYRO_ODR_12;
round_rate = 12;
}
data->gyro_hz = round_rate;
return cfg->bus_io->update(&cfg->bus, REG_GYRO_CONFIG0, (uint8_t)MASK_GYRO_ODR, temp);
}
static int icm40627_sensor_init(const struct device *dev)
{
int res;
uint8_t value;
struct icm40627_data *data = dev->data;
const struct icm40627_config *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 = cfg->bus_io->write(&cfg->bus, 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);
/* always use internal RC oscillator */
res = cfg->bus_io->write(&cfg->bus, REG_INTF_CONFIG1,
(uint8_t)FIELD_PREP(MASK_CLKSEL, BIT_CLKSEL_INT_RC));
if (res) {
LOG_ERR("write REG_INTF_CONFIG1 failed");
return res;
}
/* clear reset done int flag */
res = cfg->bus_io->read(&cfg->bus, REG_INT_STATUS, &value, 1);
if (res) {
LOG_ERR("read REG_INT_STATUS failed");
return res;
}
if (FIELD_GET(BIT_STATUS_RESET_DONE_INT, value) != 1) {
LOG_ERR("Unexpected RESET_DONE_INT value, %i", value);
return -EINVAL;
}
res = cfg->bus_io->read(&cfg->bus, REG_WHO_AM_I, &value, 1);
if (res) {
LOG_ERR("read WHO_AM_I failed");
return res;
}
if (value != WHO_AM_I_ICM40627) {
LOG_ERR("Invalid WHO_AM_I value, was %i but expected %i", value, WHO_AM_I_ICM40627);
return -EINVAL;
}
LOG_DBG("device id: 0x%02X", value);
res = icm40627_set_accel_fs(dev, data->accel_fs);
if (res) {
LOG_ERR("set accel fs failed");
return res;
}
res = icm40627_set_accel_odr(dev, data->accel_hz);
if (res) {
LOG_ERR("set accel odr failed");
return res;
}
res = icm40627_set_gyro_fs(dev, data->gyro_fs);
if (res) {
LOG_ERR("set gyro fs failed");
return res;
}
res = icm40627_set_gyro_odr(dev, data->gyro_hz);
if (res) {
LOG_ERR("set gyro odr failed");
return res;
}
return 0;
}
static int icm40627_turn_on_sensor(const struct device *dev)
{
const struct icm40627_config *cfg = dev->config;
uint8_t value;
int res;
value = FIELD_PREP(MASK_ACCEL_MODE, BIT_ACCEL_MODE_LNM) |
FIELD_PREP(MASK_GYRO_MODE, BIT_GYRO_MODE_LNM);
res = cfg->bus_io->update(&cfg->bus, REG_PWR_MGMT0,
(uint8_t)(MASK_ACCEL_MODE | MASK_GYRO_MODE), value);
if (res) {
LOG_ERR("write REG_PWR_MGMT0 failed");
return res;
}
/*
* Accelerometer sensor need at least 10ms startup time
* Gyroscope sensor need at least 30ms startup time
*/
k_msleep(40);
return 0;
}
static void icm40627_convert_accel(struct sensor_value *val, int16_t raw_val,
uint16_t sensitivity_shift)
{
/* see datasheet section 3.2 for details */
int64_t conv_val = ((int64_t)raw_val * SENSOR_G) >> sensitivity_shift;
val->val1 = conv_val / 1000000LL;
val->val2 = conv_val % 1000000LL;
}
static void icm40627_convert_gyro(struct sensor_value *val, int16_t raw_val,
uint16_t sensitivity_x10)
{
/* see datasheet section 3.1 for details */
int64_t conv_val = ((int64_t)raw_val * SENSOR_PI * 10) / ((uint32_t)sensitivity_x10 * 180);
val->val1 = conv_val / 1000000LL;
val->val2 = conv_val % 1000000LL;
}
static inline void icm40627_convert_temp(struct sensor_value *val, int16_t raw_val)
{
/* see datasheet section 14.6 for details */
val->val1 = (((int64_t)raw_val * 100) / 13248) + 25;
val->val2 = ((((int64_t)raw_val * 100) % 13248) * 1000000) / 13248;
if (val->val2 < 0) {
val->val1--;
val->val2 += 1000000;
} else if (val->val2 >= 1000000) {
val->val1++;
val->val2 -= 1000000;
}
}
static int icm40627_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
int res = 0;
const struct icm40627_data *data = dev->data;
icm40627_lock(dev);
switch (chan) {
case SENSOR_CHAN_ACCEL_XYZ:
icm40627_convert_accel(&val[0], data->accel_x, data->accel_sensitivity_shift);
icm40627_convert_accel(&val[1], data->accel_y, data->accel_sensitivity_shift);
icm40627_convert_accel(&val[2], data->accel_z, data->accel_sensitivity_shift);
break;
case SENSOR_CHAN_ACCEL_X:
icm40627_convert_accel(val, data->accel_x, data->accel_sensitivity_shift);
break;
case SENSOR_CHAN_ACCEL_Y:
icm40627_convert_accel(val, data->accel_y, data->accel_sensitivity_shift);
break;
case SENSOR_CHAN_ACCEL_Z:
icm40627_convert_accel(val, data->accel_z, data->accel_sensitivity_shift);
break;
case SENSOR_CHAN_GYRO_XYZ:
icm40627_convert_gyro(&val[0], data->gyro_x, data->gyro_sensitivity_x10);
icm40627_convert_gyro(&val[1], data->gyro_y, data->gyro_sensitivity_x10);
icm40627_convert_gyro(&val[2], data->gyro_z, data->gyro_sensitivity_x10);
break;
case SENSOR_CHAN_GYRO_X:
icm40627_convert_gyro(val, data->gyro_x, data->gyro_sensitivity_x10);
break;
case SENSOR_CHAN_GYRO_Y:
icm40627_convert_gyro(val, data->gyro_y, data->gyro_sensitivity_x10);
break;
case SENSOR_CHAN_GYRO_Z:
icm40627_convert_gyro(val, data->gyro_z, data->gyro_sensitivity_x10);
break;
case SENSOR_CHAN_DIE_TEMP:
icm40627_convert_temp(val, data->temp);
break;
default:
res = -ENOTSUP;
break;
}
icm40627_unlock(dev);
return res;
}
static int icm40627_sample_fetch_accel(const struct device *dev)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
uint8_t buffer[ACCEL_DATA_SIZE];
int res = cfg->bus_io->read(&cfg->bus, REG_ACCEL_DATA_X1, buffer, ACCEL_DATA_SIZE);
if (res) {
LOG_ERR("read accel data failed");
return res;
}
data->accel_x = (int16_t)sys_get_be16(&buffer[0]);
data->accel_y = (int16_t)sys_get_be16(&buffer[2]);
data->accel_z = (int16_t)sys_get_be16(&buffer[4]);
return 0;
}
static int icm40627_sample_fetch_gyro(const struct device *dev)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
uint8_t buffer[GYRO_DATA_SIZE];
int res = cfg->bus_io->read(&cfg->bus, REG_GYRO_DATA_X1, buffer, GYRO_DATA_SIZE);
if (res) {
LOG_ERR("read gyro data failed");
return res;
}
data->gyro_x = (int16_t)sys_get_be16(&buffer[0]);
data->gyro_y = (int16_t)sys_get_be16(&buffer[2]);
data->gyro_z = (int16_t)sys_get_be16(&buffer[4]);
return 0;
}
static int icm40627_sample_fetch_temp(const struct device *dev)
{
const struct icm40627_config *cfg = dev->config;
struct icm40627_data *data = dev->data;
uint8_t buffer[TEMP_DATA_SIZE];
int res = cfg->bus_io->read(&cfg->bus, REG_TEMP_DATA1, buffer, TEMP_DATA_SIZE);
if (res) {
LOG_ERR("read temp data failed");
return res;
}
data->temp = (int16_t)sys_get_be16(&buffer[0]);
return 0;
}
static int icm40627_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
uint8_t status;
const struct icm40627_config *cfg = dev->config;
icm40627_lock(dev);
int res = cfg->bus_io->read(&cfg->bus, REG_INT_STATUS, &status, 1);
if (res) {
LOG_ERR("read INT_STATUS failed");
goto cleanup;
}
if (!FIELD_GET(BIT_INT_STATUS_DATA_RDY_INT, status)) {
res = -EBUSY;
goto cleanup;
}
switch (chan) {
case SENSOR_CHAN_ALL:
res = icm40627_sample_fetch_accel(dev);
if (res) {
break;
}
res = icm40627_sample_fetch_gyro(dev);
if (res) {
break;
}
res = icm40627_sample_fetch_temp(dev);
break;
case SENSOR_CHAN_ACCEL_XYZ:
case SENSOR_CHAN_ACCEL_X:
case SENSOR_CHAN_ACCEL_Y:
case SENSOR_CHAN_ACCEL_Z:
res = icm40627_sample_fetch_accel(dev);
break;
case SENSOR_CHAN_GYRO_XYZ:
case SENSOR_CHAN_GYRO_X:
case SENSOR_CHAN_GYRO_Y:
case SENSOR_CHAN_GYRO_Z:
res = icm40627_sample_fetch_gyro(dev);
break;
case SENSOR_CHAN_DIE_TEMP:
res = icm40627_sample_fetch_temp(dev);
break;
default:
res = -ENOTSUP;
break;
}
cleanup:
icm40627_unlock(dev);
return res;
}
static int icm40627_attr_set(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr, const struct sensor_value *val)
{
int res = 0;
__ASSERT_NO_MSG(val != NULL);
icm40627_lock(dev);
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) {
res = icm40627_set_accel_odr(dev, val->val1);
} else if (attr == SENSOR_ATTR_FULL_SCALE) {
res = icm40627_set_accel_fs(dev, sensor_ms2_to_g(val));
} else {
LOG_ERR("Unsupported accel 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) {
res = icm40627_set_gyro_odr(dev, val->val1);
} else if (attr == SENSOR_ATTR_FULL_SCALE) {
res = icm40627_set_gyro_fs(dev, sensor_rad_to_degrees(val));
} else {
LOG_ERR("Unsupported gyro attribute");
res = -ENOTSUP;
}
break;
default:
LOG_ERR("Unsupported channel");
res = -ENOTSUP;
break;
}
icm40627_unlock(dev);
return res;
}
static int icm40627_attr_get(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr, struct sensor_value *val)
{
const struct icm40627_data *data = dev->data;
int res = 0;
__ASSERT_NO_MSG(val != NULL);
icm40627_lock(dev);
val->val2 = 0;
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) {
val->val1 = data->accel_hz;
} else if (attr == SENSOR_ATTR_FULL_SCALE) {
val->val1 = data->accel_fs;
} else {
LOG_ERR("Unsupported accel 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) {
val->val1 = data->gyro_hz;
} else if (attr == SENSOR_ATTR_FULL_SCALE) {
val->val1 = data->gyro_fs;
} else {
LOG_ERR("Unsupported gyro attribute");
res = -ENOTSUP;
}
break;
default:
LOG_ERR("Unsupported channel");
res = -ENOTSUP;
break;
}
icm40627_unlock(dev);
return res;
}
static inline int icm40627_bus_check(const struct device *dev)
{
const struct icm40627_config *cfg = dev->config;
return cfg->bus_io->check(&cfg->bus);
}
static int icm40627_init(const struct device *dev)
{
if (icm40627_bus_check(dev) < 0) {
LOG_ERR("Bus is not ready");
return -ENODEV;
}
if (icm40627_sensor_init(dev)) {
LOG_ERR("Could not initialize sensor");
return -EIO;
}
#ifdef CONFIG_ICM40627_TRIGGER
if (icm40627_trigger_init(dev)) {
LOG_ERR("Failed to initialize interrupts.");
return -EIO;
}
if (icm40627_trigger_enable_interrupt(dev)) {
LOG_ERR("Failed to enable interrupts");
return -EIO;
}
#endif
int res = icm40627_turn_on_sensor(dev);
return res;
}
#ifndef CONFIG_ICM40627_TRIGGER
void icm40627_lock(const struct device *dev)
{
ARG_UNUSED(dev);
}
void icm40627_unlock(const struct device *dev)
{
ARG_UNUSED(dev);
}
#endif
static DEVICE_API(sensor, icm40627_driver_api) = {
#ifdef CONFIG_ICM40627_TRIGGER
.trigger_set = icm40627_trigger_set,
#endif
.sample_fetch = icm40627_sample_fetch,
.channel_get = icm40627_channel_get,
.attr_set = icm40627_attr_set,
.attr_get = icm40627_attr_get,
};
#define ICM40627_INIT(inst) \
static struct icm40627_data icm40627_data_##inst = { \
.accel_hz = DT_INST_PROP(inst, accel_hz), \
.accel_fs = DT_INST_PROP(inst, accel_fs), \
.gyro_hz = DT_INST_PROP(inst, gyro_hz), \
.gyro_fs = DT_INST_PROP(inst, gyro_fs), \
}; \
\
static const struct icm40627_config icm40627_cfg_##inst = { \
.bus.i2c = I2C_DT_SPEC_INST_GET(inst), \
.bus_io = &icm40627_bus_io_i2c, \
.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, icm40627_init, NULL, &icm40627_data_##inst, \
&icm40627_cfg_##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &icm40627_driver_api);
DT_INST_FOREACH_STATUS_OKAY(ICM40627_INIT)

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_ICM40627_H_
#define ZEPHYR_DRIVERS_SENSOR_ICM40627_H_
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/kernel.h>
#define ICM40627_BUS_SPI DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(invensense_icm40627, spi)
#define ICM40627_BUS_I2C DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(invensense_icm40627, i2c)
union icm40627_bus {
#if ICM40627_BUS_I2C
struct i2c_dt_spec i2c;
#endif
};
typedef int (*icm40627_bus_check_fn)(const union icm40627_bus *bus);
typedef int (*icm40627_reg_read_fn)(const union icm40627_bus *bus, uint16_t reg, uint8_t *data,
size_t size);
typedef int (*icm40627_reg_write_fn)(const union icm40627_bus *bus, uint16_t reg, uint8_t data);
typedef int (*icm40627_reg_update_fn)(const union icm40627_bus *bus, uint16_t reg, uint8_t mask,
uint8_t data);
struct icm40627_bus_io {
icm40627_bus_check_fn check;
icm40627_reg_read_fn read;
icm40627_reg_write_fn write;
icm40627_reg_update_fn update;
};
#if ICM40627_BUS_I2C
extern const struct icm40627_bus_io icm40627_bus_io_i2c;
#endif
struct icm40627_data {
int16_t accel_x;
int16_t accel_y;
int16_t accel_z;
uint16_t accel_sensitivity_shift;
uint16_t accel_hz;
uint16_t accel_fs;
int16_t gyro_x;
int16_t gyro_y;
int16_t gyro_z;
uint16_t gyro_sensitivity_x10;
uint16_t gyro_hz;
uint16_t gyro_fs;
int16_t temp;
#ifdef CONFIG_ICM40627_TRIGGER
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
#ifdef CONFIG_ICM40627_TRIGGER_OWN_THREAD
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ICM40627_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#endif
#ifdef CONFIG_ICM40627_TRIGGER_GLOBAL_THREAD
struct k_work work;
#endif
};
struct icm40627_config {
union icm40627_bus bus;
const struct icm40627_bus_io *bus_io;
struct gpio_dt_spec gpio_int;
};
#endif /* ZEPHYR_DRIVERS_SENSOR_ICM40627_H_ */

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Bus-specific functionality for ICM40627 accessed via I2C.
*/
#include "icm40627.h"
#include "icm40627_reg.h"
#if ICM40627_BUS_I2C
static inline int icm40627_bus_check_i2c(const union icm40627_bus *bus)
{
return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV;
}
static inline int i2c_read_bank(const union icm40627_bus *bus, uint8_t reg, uint8_t bank,
uint8_t *buf, size_t len)
{
int res = i2c_reg_write_byte_dt(&bus->i2c, REG_REG_BANK_SEL, bank);
if (res) {
return res;
}
for (size_t i = 0; i < len; i++) {
uint8_t addr = reg + i;
res = i2c_reg_read_byte_dt(&bus->i2c, addr, &buf[i]);
if (res) {
return res;
}
}
return 0;
}
static inline int icm40627_reg_read_i2c(const union icm40627_bus *bus, uint16_t reg, uint8_t *data,
size_t len)
{
int res = 0;
uint8_t bank = FIELD_GET(REG_BANK_MASK, reg);
uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg);
res = i2c_read_bank(bus, address, bank, data, len);
return res;
}
static inline int i2c_write_bank(const union icm40627_bus *bus, uint16_t reg, uint8_t bank,
uint8_t buf)
{
int res = i2c_reg_write_byte_dt(&bus->i2c, REG_REG_BANK_SEL, bank);
if (res) {
return res;
}
res = i2c_reg_write_byte_dt(&bus->i2c, reg, buf);
if (res) {
return res;
}
return 0;
}
static inline int icm40627_reg_write_i2c(const union icm40627_bus *bus, uint16_t reg, uint8_t data)
{
int res = 0;
uint8_t bank = FIELD_GET(REG_BANK_MASK, reg);
uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg);
res = i2c_write_bank(bus, address, bank, data);
return res;
}
static inline int icm40627_reg_update_i2c(const union icm40627_bus *bus, uint16_t reg, uint8_t mask,
uint8_t val)
{
return i2c_reg_update_byte_dt(&bus->i2c, reg, mask, val);
}
const struct icm40627_bus_io icm40627_bus_io_i2c = {
.check = icm40627_bus_check_i2c,
.read = icm40627_reg_read_i2c,
.write = icm40627_reg_write_i2c,
.update = icm40627_reg_update_i2c,
};
#endif /* ICM40627_BUS_I2C */

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_ICM40627_REG_H_
#define ZEPHYR_DRIVERS_SENSOR_ICM40627_REG_H_
#include <zephyr/sys/util.h>
/* Helper macros for addressing registers in BANKs 1-4 */
#define REG_ADDRESS_MASK GENMASK(7, 0)
#define REG_BANK_MASK GENMASK(15, 8)
/* BANK 0 */
#define REG_DEVICE_CONFIG 0x11
#define REG_DRIVE_CONFIG 0x13
#define REG_INT_CONFIG 0x14
#define REG_FIFO_CONFIG 0x16
#define REG_TEMP_DATA1 0x1D
#define REG_ACCEL_DATA_X1 0x1F
#define REG_GYRO_DATA_X1 0x25
#define REG_TMST_FSYNCH 0x2B
#define REG_INT_STATUS 0x2D
#define REG_FIFO_COUNTH 0x2E
#define REG_FIFO_COUNTL 0x2F
#define REG_FIFO_DATA 0x30
#define REG_APEX_DATA0 0x31
#define REG_APEX_DATA1 0x32
#define REG_APEX_DATA2 0x33
#define REG_APEX_DATA3 0x34
#define REG_APEX_DATA4 0x35
#define REG_APEX_DATA5 0x36
#define REG_INT_STATUS2 0x37
#define REG_INT_STATUS3 0x38
#define REG_SIGNAL_PATH_RESET 0x4B
#define REG_INTF_CONFIG0 0x4C
#define REG_INTF_CONFIG1 0x4D
#define REG_PWR_MGMT0 0x4E
#define REG_GYRO_CONFIG0 0x4F
#define REG_ACCEL_CONFIG0 0x50
#define REG_GYRO_CONFIG1 0x51
#define REG_ACCEL_GYRO_CONFIG0 0x52
#define REG_ACCEL_CONFIG1 0x53
#define REG_TMST_CONFIG 0x54
#define REG_APEX_CONFIG0 0x56
#define REG_SMD_CONFIG 0x57
#define REG_FIFO_CONFIG1 0x5F
#define REG_FIFO_CONFIG2 0x60
#define REG_FSYNC_CONFIG 0x62
#define REG_INT_CONFIG0 0x63
#define REG_INT_CONFIG1 0x64
#define REG_INT_SOURCE0 0x65
#define REG_INT_SOURCE1 0x66
#define REG_INT_SOURCE2 0x67
#define REG_INT_SOURCE3 0x68
#define REG_INT_SOURCE4 0x69
#define REG_INT_SOURCE5 0x6A
#define REG_FIFO_LOST_PKT0 0x6C
#define REG_SELF_TEST_CONFIG 0x70
#define REG_WHO_AM_I 0x75
#define REG_REG_BANK_SEL 0x76
/* BANK 1 */
#define REG_GYRO_CONFIG_STATIC2_B1 0x0B
#define REG_GYRO_CONFIG_STATIC3_B1 0x0C
#define REG_GYRO_CONFIG_STATIC4_B1 0x0D
#define REG_GYRO_CONFIG_STATIC5_B1 0x0E
#define REG_XG_ST_DATA_B1 0x5F
#define REG_YG_ST_DATA_B1 0x60
#define REG_ZG_ST_DATA_B1 0x61
#define REG_TMST_VAL0_B1 0x62
#define REG_INTF_CONFIG4_B1 0x7A
#define REG_INTF_CONFIG5_B1 0x7B
#define REG_INTF_CONFIG6_B1 0x7C
/* BANK 2 */
#define REG_ACCEL_CONFIG_STATIC2_B2 0x03
#define REG_ACCEL_CONFIG_STATIC3_B2 0x04
#define REG_ACCEL_CONFIG_STATIC4_B2 0x05
#define REG_ACCEL_CONFIG_STATIC0_B2 0x39
#define REG_XA_ST_DATA_B2 0x3B
#define REG_YA_ST_DATA_B2 0x3C
#define REG_ZA_ST_DATA_B2 0x3D
/* BANK 4 */
#define REG_APEX_CONFIG1_B4 0x40
#define REG_APEX_CONFIG2_B4 0x41
#define REG_APEX_CONFIG3_B4 0x42
#define REG_APEX_CONFIG4_B4 0x43
#define REG_APEX_CONFIG5_B4 0x44
#define REG_APEX_CONFIG6_B4 0x45
#define REG_APEX_CONFIG7_B4 0x46
#define REG_APEX_CONFIG8_B4 0x47
#define REG_APEX_CONFIG9_B4 0x48
#define REG_ACCEL_WOM_X_THR_B4 0x4A
#define REG_ACCEL_WOM_Y_THR_B4 0x4B
#define REG_ACCEL_WOM_Z_THR_B4 0x4C
#define REG_INT_SOURCE6_B4 0x4D
#define REG_INT_SOURCE7_B4 0x4E
#define REG_INT_SOURCE8_B4 0x4F
#define REG_INT_SOURCE9_B4 0x50
#define REG_INT_SOURCE10_B4 0x51
#define REG_OFFSET_USER_0_B4 0x77
#define REG_OFFSET_USER_1_B4 0x78
#define REG_OFFSET_USER_2_B4 0x79
#define REG_OFFSET_USER_3_B4 0x7A
#define REG_OFFSET_USER_4_B4 0x7B
#define REG_OFFSET_USER_5_B4 0x7C
#define REG_OFFSET_USER_6_B4 0x7D
#define REG_OFFSET_USER_7_B4 0x7E
#define REG_OFFSET_USER_8_B4 0x7F
/* Bank0 REG_SIGNAL_PATH_RESET */
#define BIT_FIFO_FLUSH BIT(2)
#define BIT_SOFT_RESET BIT(0)
/* Bank0 REG_INST_STATUS */
#define BIT_STATUS_RESET_DONE_INT BIT(4)
/* Bank0 REG_INT_CONFIG */
#define BIT_INT1_POLARITY BIT(0)
#define BIT_INT1_DRIVE_CIRCUIT BIT(1)
#define BIT_INT1_MODE BIT(2)
#define BIT_INT2_POLARITY BIT(3)
#define BIT_INT2_DRIVE_CIRCUIT BIT(4)
#define BIT_INT2_MODE BIT(5)
/* Bank0 REG_PWR_MGMT_0 */
#define MASK_ACCEL_MODE GENMASK(1, 0)
#define BIT_ACCEL_MODE_OFF 0x00
#define BIT_ACCEL_MODE_LPM 0x02
#define BIT_ACCEL_MODE_LNM 0x03
#define MASK_GYRO_MODE GENMASK(3, 2)
#define BIT_GYRO_MODE_OFF 0x00
#define BIT_GYRO_MODE_STBY 0x01
#define BIT_GYRO_MODE_LNM 0x03
#define BIT_IDLE BIT(4)
#define BIT_ACCEL_LP_CLK_SEL BIT(7)
/* Bank0 REG_INT_SOURCE0 */
#define BIT_INT_AGC_RDY_INT1_EN BIT(0)
#define BIT_INT_FIFO_FULL_INT1_EN BIT(1)
#define BIT_INT_FIFO_THS_INT1_EN BIT(2)
#define BIT_INT_DRDY_INT1_EN BIT(3)
#define BIT_INT_RESET_DONE_INT1_EN BIT(4)
#define BIT_INT_PLL_RDY_INT1_EN BIT(5)
#define BIT_INT_FSYNC_INT1_EN BIT(6)
#define BIT_INT_ST_INT1_EN BIT(7)
/* Bank0 REG_INT_STATUS_DATA_RDY_INT */
#define BIT_INT_STATUS_DATA_RDY_INT BIT(3)
/* Bank9 REG_INTF_CONFIG1 */
#define BIT_ACCELL_LP_CLK_SEL BIT(3)
#define MASK_CLKSEL GENMASK(1, 0)
#define BIT_CLKSEL_INT_RC 0x00
#define BIT_CLKSEL_PLL_OR_RC 0x01
#define BIT_CLKSEL_DISABLE 0x11
/* Bank0 REG_INT_STATUS */
#define BIT_INT_STATUS_AGC_RDY BIT(0)
#define BIT_INT_STATUS_FIFO_FULL BIT(1)
#define BIT_INT_STATUS_FIFO_THS BIT(2)
#define BIT_INT_STATUS_RESET_DONE BIT(4)
#define BIT_INT_STATUS_PLL_RDY BIT(5)
#define BIT_INT_STATUS_FSYNC BIT(6)
#define BIT_INT_STATUS_ST BIT(7)
/* Bank0 REG_INT_STATUS2 */
#define BIT_INT_STATUS_WOM_Z BIT(0)
#define BIT_INT_STATUS_WOM_Y BIT(1)
#define BIT_INT_STATUS_WOM_X BIT(2)
#define BIT_INT_STATUS_SMD BIT(3)
/* Bank0 REG_INT_STATUS3 */
#define BIT_INT_STATUS_LOWG_DET BIT(1)
#define BIT_INT_STATUS_FF_DET BIT(2)
#define BIT_INT_STATUS_TILT_DET BIT(3)
#define BIT_INT_STATUS_STEP_CNT_OVFL BIT(4)
#define BIT_INT_STATUS_STEP_DET BIT(5)
/* Bank0 REG_ACCEL_CONFIG0 */
#define MASK_ACCEL_UI_FS_SEL GENMASK(6, 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 MASK_ACCEL_ODR GENMASK(3, 0)
#define BIT_ACCEL_ODR_8000 0x03
#define BIT_ACCEL_ODR_4000 0x04
#define BIT_ACCEL_ODR_2000 0x05
#define BIT_ACCEL_ODR_1000 0x06
#define BIT_ACCEL_ODR_200 0x07
#define BIT_ACCEL_ODR_100 0x08
#define BIT_ACCEL_ODR_50 0x09
#define BIT_ACCEL_ODR_25 0x0A
#define BIT_ACCEL_ODR_12 0x0B
#define BIT_ACCEL_ODR_6 0x0C
#define BIT_ACCEL_ODR_3 0x0D
#define BIT_ACCEL_ODR_1 0x0E
#define BIT_ACCEL_ODR_500 0x0F
/* Bank0 REG_GYRO_CONFIG0 */
#define MASK_GYRO_UI_FS_SEL GENMASK(6, 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 0x05
#define BIT_GYRO_UI_FS_31 0x06
#define BIT_GYRO_UI_FS_15 0x07
#define MASK_GYRO_ODR GENMASK(3, 0)
#define BIT_GYRO_ODR_8000 0x03
#define BIT_GYRO_ODR_4000 0x04
#define BIT_GYRO_ODR_2000 0x05
#define BIT_GYRO_ODR_1000 0x06
#define BIT_GYRO_ODR_200 0x07
#define BIT_GYRO_ODR_100 0x08
#define BIT_GYRO_ODR_50 0x09
#define BIT_GYRO_ODR_25 0x0A
#define BIT_GYRO_ODR_12 0x0B
#define BIT_GYRO_ODR_500 0x0F
/* misc. defines */
#define WHO_AM_I_ICM40627 0x4E
#define MIN_ACCEL_SENS_SHIFT 10
#define ACCEL_DATA_SIZE 6
#define GYRO_DATA_SIZE 6
#define TEMP_DATA_SIZE 2
#define MCLK_POLL_INTERVAL_US 250
#define MCLK_POLL_ATTEMPTS 100
#define SOFT_RESET_TIME_MS 2
#endif /* ZEPHYR_DRIVERS_SENSOR_ICM40627_REG_H_ */

View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/util.h>
#include "icm40627.h"
#include "icm40627_reg.h"
#include "icm40627_trigger.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(ICM40627, CONFIG_SENSOR_LOG_LEVEL);
static void icm40627_gpio_callback(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
ARG_UNUSED(dev);
ARG_UNUSED(pins);
struct icm40627_data *data = CONTAINER_OF(cb, struct icm40627_data, gpio_cb);
#if defined(CONFIG_ICM40627_TRIGGER_OWN_THREAD)
k_sem_give(&data->gpio_sem);
#elif defined(CONFIG_ICM40627_TRIGGER_GLOBAL_THREAD)
k_work_submit(&data->work);
#endif
}
static void icm40627_thread_cb(const struct device *dev)
{
struct icm40627_data *data = dev->data;
const struct icm40627_config *cfg = dev->config;
icm40627_lock(dev);
gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
if (data->data_ready_handler) {
data->data_ready_handler(dev, data->data_ready_trigger);
}
gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE);
icm40627_unlock(dev);
}
#if defined(CONFIG_ICM40627_TRIGGER_OWN_THREAD)
static void icm40627_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p2);
ARG_UNUSED(p3);
struct icm40627_data *data = p1;
while (1) {
k_sem_take(&data->gpio_sem, K_FOREVER);
icm40627_thread_cb(data->dev);
}
}
#elif defined(CONFIG_ICM40627_TRIGGER_GLOBAL_THREAD)
static void icm40627_work_handler(struct k_work *work)
{
struct icm40627_data *data = CONTAINER_OF(work, struct icm40627_data, work);
icm40627_thread_cb(data->dev);
}
#endif
int icm40627_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
int res = 0;
struct icm40627_data *data = dev->data;
const struct icm40627_config *cfg = dev->config;
if (!handler) {
return -EINVAL;
}
icm40627_lock(dev);
gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
switch (trig->type) {
case SENSOR_TRIG_DATA_READY:
data->data_ready_handler = handler;
data->data_ready_trigger = trig;
break;
default:
res = -ENOTSUP;
break;
}
gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE);
icm40627_unlock(dev);
return res;
}
int icm40627_trigger_init(const struct device *dev)
{
struct icm40627_data *data = dev->data;
const struct icm40627_config *cfg = dev->config;
int res = 0;
if (!cfg->gpio_int.port) {
LOG_ERR("trigger enabled but no interrupt gpio supplied");
return -ENODEV;
}
if (!gpio_is_ready_dt(&cfg->gpio_int)) {
LOG_ERR("gpio_int gpio not ready");
return -ENODEV;
}
data->dev = dev;
gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
gpio_init_callback(&data->gpio_cb, icm40627_gpio_callback, BIT(cfg->gpio_int.pin));
res = gpio_add_callback(cfg->gpio_int.port, &data->gpio_cb);
if (res < 0) {
LOG_ERR("Failed to set gpio callback");
return res;
}
k_mutex_init(&data->mutex);
#if defined(CONFIG_ICM40627_TRIGGER_OWN_THREAD)
k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&data->thread, data->thread_stack, CONFIG_ICM40627_THREAD_STACK_SIZE,
icm40627_thread, data, NULL, NULL,
K_PRIO_COOP(CONFIG_ICM40627_THREAD_PRIORITY), 0, K_NO_WAIT);
#elif defined(CONFIG_ICM40627_TRIGGER_GLOBAL_THREAD)
data->work.handler = icm40627_work_handler;
#endif
return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE);
}
int icm40627_trigger_enable_interrupt(const struct device *dev)
{
int res;
const struct icm40627_config *cfg = dev->config;
/* pulse-mode (auto clearing), push-pull and active-high */
res = cfg->bus_io->write(&cfg->bus, REG_INT_CONFIG,
BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY);
if (res) {
return res;
}
/* enable data ready interrupt on INT1 pin */
return cfg->bus_io->write(&cfg->bus, REG_INT_SOURCE0, BIT_INT_DRDY_INT1_EN);
}
void icm40627_lock(const struct device *dev)
{
struct icm40627_data *data = dev->data;
k_mutex_lock(&data->mutex, K_FOREVER);
}
void icm40627_unlock(const struct device *dev)
{
struct icm40627_data *data = dev->data;
k_mutex_unlock(&data->mutex);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 PHYTEC America LLC
* Author: Florijan Plohl <florijan.plohl@norik.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_ICM40627_TRIGGER_H_
#define ZEPHYR_DRIVERS_SENSOR_ICM40627_TRIGGER_H_
#include <zephyr/device.h>
/** implement the trigger_set sensor api function */
int icm40627_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
/**
* @brief initialize the icm40627 trigger system
*
* @param dev icm40627 device pointer
* @return int 0 on success, negative error code otherwise
*/
int icm40627_trigger_init(const struct device *dev);
/**
* @brief enable the trigger gpio interrupt
*
* @param dev icm40627 device pointer
* @return int 0 on success, negative error code otherwise
*/
int icm40627_trigger_enable_interrupt(const struct device *dev);
/**
* @brief lock access to the icm40627 device driver
*
* @param dev icm40627 device pointer
*/
void icm40627_lock(const struct device *dev);
/**
* @brief lock access to the icm40627 device driver
*
* @param dev icm40627 device pointer
*/
void icm40627_unlock(const struct device *dev);
#endif /* ZEPHYR_DRIVERS_SENSOR_ICM40627_TRIGGER_H_ */

View file

@ -0,0 +1,8 @@
# Copyright (c) 2025 PHYTEC America LLC
# SPDX-License-Identifier: Apache-2.0
description: ICM-40627 motion tracking device
compatible: "invensense,icm40627"
include: [i2c-device.yaml, "invensense,icm40627.yaml"]

View file

@ -0,0 +1,85 @@
# Copyright (c) 2025 PHYTEC America LLC
# SPDX-License-Identifier: Apache-2.0
description: ICM-40627 motion tracking device
include: [sensor-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.
accel-hz:
type: int
required: true
description: |
Default frequency of accelerometer. (Unit - Hz)
Maps to ACCEL_ODR field in ACCEL_CONFIG0 setting
Power-on reset value is 1000.
enum:
- 1
- 3
- 6
- 12
- 25
- 50
- 100
- 200
- 500
- 1000
- 2000
- 4000
- 8000
gyro-hz:
type: int
required: true
description: |
Default frequency of gyroscope. (Unit - Hz)
Maps to GYRO_ODR field in GYRO_CONFIG0 setting
Power-on reset value is 1000.
enum:
- 12
- 25
- 50
- 100
- 200
- 500
- 1000
- 2000
- 4000
- 8000
accel-fs:
type: int
required: true
description: |
Default full scale of accelerometer. (Unit - g)
Maps to ACCEL_FS_SEL field in ACCEL_CONFIG0 setting
Power-on reset value is 16
enum:
- 16
- 8
- 4
- 2
gyro-fs:
type: int
required: true
description: |
Default full scale of gyroscope. (Unit - DPS)
Maps to GYRO_FS_SEL field in GYRO_CONFIG0 setting
Power-on reset value is 2000
enum:
- 2000
- 1000
- 500
- 250
- 125
- 62
- 31
- 15