1 /*
2 * Copyright (c) 2024 TDK Invensense
3 * Copyright (c) 2022 Esco Medical ApS
4 * Copyright (c) 2020 TDK Invensense
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/init.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/drivers/sensor/icm42x70.h>
17 #include <zephyr/drivers/sensor/tdk_apex.h>
18
19 #include "icm42x70.h"
20 #include "icm42x70_trigger.h"
21 #include "icm42670.h"
22
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(ICM42X70, CONFIG_SENSOR_LOG_LEVEL);
25
26 /* Convert DT enum to sensor ODR selection */
27 #define ICM42X70_CONVERT_ENUM_TO_ODR_POS (4)
28
29 /* Maximum bytes to read/write on ICM42X70 serial interface */
30 #define ICM42X70_SERIAL_INTERFACE_MAX_READ (1024 * 32)
31 #define ICM42X70_SERIAL_INTERFACE_MAX_WRITE (1024 * 32)
32
icm42x70_reg_read(const struct device * dev,uint8_t reg,uint8_t * buf,uint32_t size)33 static inline int icm42x70_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf,
34 uint32_t size)
35 {
36 const struct icm42x70_config *cfg = dev->config;
37
38 return cfg->bus_io->read(&cfg->bus, reg, buf, size);
39 }
40
inv_io_hal_read_reg(struct inv_imu_serif * serif,uint8_t reg,uint8_t * rbuffer,uint32_t rlen)41 static inline int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t *rbuffer,
42 uint32_t rlen)
43 {
44 return icm42x70_reg_read(serif->context, reg, rbuffer, rlen);
45 }
46
icm42x70_reg_write(const struct device * dev,uint8_t reg,const uint8_t * buf,uint32_t size)47 static inline int icm42x70_reg_write(const struct device *dev, uint8_t reg, const uint8_t *buf,
48 uint32_t size)
49 {
50 const struct icm42x70_config *cfg = dev->config;
51
52 return cfg->bus_io->write(&cfg->bus, reg, (uint8_t *)buf, size);
53 }
54
inv_io_hal_write_reg(struct inv_imu_serif * serif,uint8_t reg,const uint8_t * wbuffer,uint32_t wlen)55 static inline int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg,
56 const uint8_t *wbuffer, uint32_t wlen)
57 {
58 return icm42x70_reg_write(serif->context, reg, wbuffer, wlen);
59 }
60
inv_imu_sleep_us(uint32_t us)61 void inv_imu_sleep_us(uint32_t us)
62 {
63 k_sleep(K_USEC(us));
64 }
65
inv_imu_get_time_us(void)66 uint64_t inv_imu_get_time_us(void)
67 {
68 /* returns the elapsed time since the system booted, in milliseconds */
69 return k_uptime_get() * 1000;
70 }
71
convert_dt_enum_to_freq(uint8_t val)72 static uint16_t convert_dt_enum_to_freq(uint8_t val)
73 {
74 uint16_t freq;
75
76 switch (val) {
77 case 0:
78 freq = 0;
79 break;
80 case 1:
81 freq = 1600;
82 break;
83 case 2:
84 freq = 800;
85 break;
86 case 3:
87 freq = 400;
88 break;
89 case 4:
90 freq = 200;
91 break;
92 case 5:
93 freq = 100;
94 break;
95 case 6:
96 freq = 50;
97 break;
98 case 7:
99 freq = 25;
100 break;
101 case 8:
102 freq = 12;
103 break;
104 case 9:
105 freq = 6;
106 break;
107 case 10:
108 freq = 3;
109 break;
110 case 11:
111 freq = 1;
112 break;
113 default:
114 freq = 0;
115 break;
116 }
117 return freq;
118 }
119
convert_freq_to_bitfield(uint32_t val,uint16_t * freq)120 uint32_t convert_freq_to_bitfield(uint32_t val, uint16_t *freq)
121 {
122 uint32_t odr_bitfield = 0;
123
124 if (val < 3 && val >= 1) {
125 odr_bitfield = ACCEL_CONFIG0_ODR_1_5625_HZ; /*(= GYRO_CONFIG0_ODR_1_5625_HZ )*/
126 *freq = 1;
127 } else if (val < 6 && val >= 3) {
128 odr_bitfield = ACCEL_CONFIG0_ODR_3_125_HZ; /*(= GYRO_CONFIG0_ODR_3_125_HZ )*/
129 *freq = 3;
130 } else if (val < 12 && val >= 6) {
131 odr_bitfield = ACCEL_CONFIG0_ODR_6_25_HZ; /*(= GYRO_CONFIG0_ODR_6_25_HZ )*/
132 *freq = 6;
133 } else if (val < 25 && val >= 12) {
134 odr_bitfield = ACCEL_CONFIG0_ODR_12_5_HZ; /*(= GYRO_CONFIG0_ODR_12_5_HZ )*/
135 *freq = 12;
136 } else if (val < 50 && val >= 25) {
137 odr_bitfield = ACCEL_CONFIG0_ODR_25_HZ; /*(= GYRO_CONFIG0_ODR_25_HZ )*/
138 *freq = 25;
139 } else if (val < 100 && val >= 50) {
140 odr_bitfield = ACCEL_CONFIG0_ODR_50_HZ; /*(GYRO_CONFIG0_ODR_50_HZ)*/
141 *freq = 50;
142 } else if (val < 200 && val >= 100) {
143 odr_bitfield = ACCEL_CONFIG0_ODR_100_HZ; /*(= GYRO_CONFIG0_ODR_100_HZ )*/
144 *freq = 100;
145 } else if (val < 400 && val >= 200) {
146 odr_bitfield = ACCEL_CONFIG0_ODR_200_HZ; /*(= GYRO_CONFIG0_ODR_200_HZ )*/
147 *freq = 200;
148 } else if (val < 800 && val >= 400) {
149 odr_bitfield = ACCEL_CONFIG0_ODR_400_HZ; /*(= GYRO_CONFIG0_ODR_400_HZ )*/
150 *freq = 400;
151 } else if (val < 1600 && val >= 800) {
152 odr_bitfield = ACCEL_CONFIG0_ODR_800_HZ; /*(= GYRO_CONFIG0_ODR_800_HZ )*/
153 *freq = 800;
154 } else if (val == 1600) {
155 odr_bitfield = ACCEL_CONFIG0_ODR_1600_HZ; /*(= GYRO_CONFIG0_ODR_1600_HZ )*/
156 *freq = 1600;
157 }
158 return odr_bitfield;
159 }
160
convert_acc_fs_to_bitfield(uint32_t val,uint8_t * fs)161 static uint32_t convert_acc_fs_to_bitfield(uint32_t val, uint8_t *fs)
162 {
163 uint32_t bitfield = 0;
164
165 if (val < 4 && val >= 2) {
166 bitfield = ACCEL_CONFIG0_FS_SEL_2g;
167 *fs = 2;
168 } else if (val < 8 && val >= 4) {
169 bitfield = ACCEL_CONFIG0_FS_SEL_4g;
170 *fs = 4;
171 } else if (val < 16 && val >= 8) {
172 bitfield = ACCEL_CONFIG0_FS_SEL_8g;
173 *fs = 8;
174 } else if (val == 16) {
175 bitfield = ACCEL_CONFIG0_FS_SEL_16g;
176 *fs = 16;
177 }
178 return bitfield;
179 }
180
convert_ln_bw_to_bitfield(uint32_t val)181 uint32_t convert_ln_bw_to_bitfield(uint32_t val)
182 {
183 uint32_t bitfield = 0xFF;
184
185 if (val < 25 && val >= 16) {
186 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_16; /* (= GYRO_CONFIG1_GYRO_FILT_BW_16) */
187 } else if (val < 34 && val >= 25) {
188 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_25; /* (= GYRO_CONFIG1_GYRO_FILT_BW_25) */
189 } else if (val < 53 && val >= 34) {
190 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_34; /* (= GYRO_CONFIG1_GYRO_FILT_BW_34) */
191 } else if (val < 73 && val >= 53) {
192 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_53; /* (= GYRO_CONFIG1_GYRO_FILT_BW_53) */
193 } else if (val < 121 && val >= 73) {
194 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_73; /* (= GYRO_CONFIG1_GYRO_FILT_BW_73) */
195 } else if (val < 180 && val >= 121) {
196 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_121; /* (= GYRO_CONFIG1_GYRO_FILT_BW_121) */
197 } else if (val == 180) {
198 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_180; /* (= GYRO_CONFIG1_GYRO_FILT_BW_180) */
199 } else if (val == 0) {
200 bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_NO_FILTER;
201 /*(= GYRO_CONFIG1_GYRO_FILT_BW_NO_FILTER)*/
202 }
203 return bitfield;
204 }
205
convert_lp_avg_to_bitfield(uint32_t val)206 static uint32_t convert_lp_avg_to_bitfield(uint32_t val)
207 {
208 uint32_t bitfield = 0xFF;
209
210 if (val < 4 && val >= 2) {
211 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_2;
212 } else if (val < 8 && val >= 4) {
213 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_4;
214 } else if (val < 16 && val >= 8) {
215 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_8;
216 } else if (val < 32 && val >= 16) {
217 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_16;
218 } else if (val < 64 && val >= 32) {
219 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_32;
220 } else if (val == 64) {
221 bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_64;
222 }
223 return bitfield;
224 }
225
convert_bitfield_to_acc_fs(uint8_t bitfield)226 static uint8_t convert_bitfield_to_acc_fs(uint8_t bitfield)
227 {
228 uint8_t acc_fs = 0;
229
230 if (bitfield == ACCEL_CONFIG0_FS_SEL_2g) {
231 acc_fs = 2;
232 } else if (bitfield == ACCEL_CONFIG0_FS_SEL_4g) {
233 acc_fs = 4;
234 } else if (bitfield == ACCEL_CONFIG0_FS_SEL_8g) {
235 acc_fs = 8;
236 } else if (bitfield == ACCEL_CONFIG0_FS_SEL_16g) {
237 acc_fs = 16;
238 }
239 return acc_fs;
240 }
241
icm42x70_set_accel_power_mode(struct icm42x70_data * drv_data,const struct sensor_value * val)242 static int icm42x70_set_accel_power_mode(struct icm42x70_data *drv_data,
243 const struct sensor_value *val)
244 {
245 if ((val->val1 == ICM42X70_LOW_POWER_MODE) &&
246 (drv_data->accel_pwr_mode != ICM42X70_LOW_POWER_MODE)) {
247 if (drv_data->accel_hz != 0) {
248 if (drv_data->accel_hz <= 400) {
249 inv_imu_enable_accel_low_power_mode(&drv_data->driver);
250 } else {
251 LOG_ERR("Not supported ATTR value");
252 return -EINVAL;
253 }
254 }
255 drv_data->accel_pwr_mode = val->val1;
256 } else if ((val->val1 == ICM42X70_LOW_NOISE_MODE) &&
257 (drv_data->accel_pwr_mode != ICM42X70_LOW_NOISE_MODE)) {
258 if (drv_data->accel_hz != 0) {
259 if (drv_data->accel_hz >= 12) {
260 inv_imu_enable_accel_low_noise_mode(&drv_data->driver);
261 } else {
262 LOG_ERR("Not supported ATTR value");
263 return -EINVAL;
264 }
265 }
266 drv_data->accel_pwr_mode = val->val1;
267 } else {
268 LOG_ERR("Not supported ATTR value");
269 return -EINVAL;
270 }
271 return 0;
272 }
273
icm42x70_set_accel_odr(struct icm42x70_data * drv_data,const struct sensor_value * val)274 static int icm42x70_set_accel_odr(struct icm42x70_data *drv_data, const struct sensor_value *val)
275 {
276 if (val->val1 <= 1600 && val->val1 >= 1) {
277 if (drv_data->accel_hz == 0) {
278 inv_imu_set_accel_frequency(
279 &drv_data->driver,
280 convert_freq_to_bitfield(val->val1, &drv_data->accel_hz));
281 if (drv_data->accel_pwr_mode == ICM42X70_LOW_POWER_MODE) {
282 inv_imu_enable_accel_low_power_mode(&drv_data->driver);
283 } else if (drv_data->accel_pwr_mode == ICM42X70_LOW_NOISE_MODE) {
284 inv_imu_enable_accel_low_noise_mode(&drv_data->driver);
285 }
286 } else {
287 inv_imu_set_accel_frequency(
288 &drv_data->driver,
289 convert_freq_to_bitfield(val->val1, &drv_data->accel_hz));
290 }
291 } else if (val->val1 == 0) {
292 inv_imu_disable_accel(&drv_data->driver);
293 drv_data->accel_hz = val->val1;
294 } else {
295 LOG_ERR("Incorrect sampling value");
296 return -EINVAL;
297 }
298 return 0;
299 }
300
icm42x70_set_accel_fs(struct icm42x70_data * drv_data,const struct sensor_value * val)301 static int icm42x70_set_accel_fs(struct icm42x70_data *drv_data, const struct sensor_value *val)
302 {
303 if (val->val1 > 16 || val->val1 < 2) {
304 LOG_ERR("Incorrect fullscale value");
305 return -EINVAL;
306 }
307 inv_imu_set_accel_fsr(&drv_data->driver,
308 convert_acc_fs_to_bitfield(val->val1, &drv_data->accel_fs));
309 LOG_DBG("Set accel full scale to: %d G", drv_data->accel_fs);
310 return 0;
311 }
312
icm42x70_accel_config(struct icm42x70_data * drv_data,enum sensor_attribute attr,const struct sensor_value * val)313 static int icm42x70_accel_config(struct icm42x70_data *drv_data, enum sensor_attribute attr,
314 const struct sensor_value *val)
315 {
316 if (attr == SENSOR_ATTR_CONFIGURATION) {
317 icm42x70_set_accel_power_mode(drv_data, val);
318
319 } else if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
320 icm42x70_set_accel_odr(drv_data, val);
321
322 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
323 icm42x70_set_accel_fs(drv_data, val);
324
325 } else if ((enum sensor_attribute_icm42x70)attr == SENSOR_ATTR_BW_FILTER_LPF) {
326 if (val->val1 > 180) {
327 LOG_ERR("Incorrect low pass filter bandwidth value");
328 return -EINVAL;
329 }
330 inv_imu_set_accel_ln_bw(&drv_data->driver, convert_ln_bw_to_bitfield(val->val1));
331
332 } else if ((enum sensor_attribute_icm42x70)attr == SENSOR_ATTR_AVERAGING) {
333 if (val->val1 > 64 || val->val1 < 2) {
334 LOG_ERR("Incorrect averaging filter value");
335 return -EINVAL;
336 }
337 inv_imu_set_accel_lp_avg(&drv_data->driver, convert_lp_avg_to_bitfield(val->val1));
338 } else {
339 LOG_ERR("Unsupported attribute");
340 return -EINVAL;
341 }
342 return 0;
343 }
344
icm42x70_sensor_init(const struct device * dev)345 static int icm42x70_sensor_init(const struct device *dev)
346 {
347 struct icm42x70_data *data = dev->data;
348 const struct icm42x70_config *config = dev->config;
349 int err = 0;
350
351 /* Initialize serial interface and device */
352 data->serif.context = (struct device *)dev;
353 data->serif.read_reg = inv_io_hal_read_reg;
354 data->serif.write_reg = inv_io_hal_write_reg;
355 data->serif.max_read = ICM42X70_SERIAL_INTERFACE_MAX_READ;
356 data->serif.max_write = ICM42X70_SERIAL_INTERFACE_MAX_WRITE;
357 data->serif.serif_type = config->serif_type;
358 err = inv_imu_init(&data->driver, &data->serif, NULL);
359 if (err < 0) {
360 LOG_ERR("Init failed: %d", err);
361 return err;
362 }
363
364 err = inv_imu_get_who_am_i(&data->driver, &data->chip_id);
365 if (err < 0) {
366 LOG_ERR("ID read failed: %d", err);
367 return err;
368 }
369
370 if (data->chip_id != data->imu_whoami) {
371 LOG_ERR("invalid WHO_AM_I value, was 0x%x but expected 0x%x for %s", data->chip_id,
372 data->imu_whoami, data->imu_name);
373 return -ENOTSUP;
374 }
375
376 LOG_DBG("\"%s\" %s OK", dev->name, data->imu_name);
377 return 0;
378 }
379
icm42x70_turn_on_sensor(const struct device * dev)380 static int icm42x70_turn_on_sensor(const struct device *dev)
381 {
382 struct icm42x70_data *data = dev->data;
383 const struct icm42x70_config *cfg = dev->config;
384 int err = 0;
385
386 err = inv_imu_set_accel_fsr(&data->driver,
387 (cfg->accel_fs << ACCEL_CONFIG0_ACCEL_UI_FS_SEL_POS));
388 data->accel_fs =
389 convert_bitfield_to_acc_fs((cfg->accel_fs << ACCEL_CONFIG0_ACCEL_UI_FS_SEL_POS));
390 if ((err < 0) || (data->accel_fs == 0)) {
391 LOG_ERR("Failed to configure accel FSR");
392 return -EIO;
393 }
394 LOG_DBG("Set accel full scale to: %d G", data->accel_fs);
395
396 #if CONFIG_USE_EMD_ICM42670
397 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
398 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
399 err = inv_imu_set_gyro_fsr(&data->driver,
400 (cfg->gyro_fs << GYRO_CONFIG0_GYRO_UI_FS_SEL_POS));
401 data->gyro_fs = convert_bitfield_to_gyr_fs(
402 (cfg->gyro_fs << GYRO_CONFIG0_GYRO_UI_FS_SEL_POS));
403 if ((err < 0) || (data->gyro_fs == 0)) {
404 LOG_ERR("Failed to configure gyro FSR");
405 return -EIO;
406 }
407 LOG_DBG("Set gyro full scale to: %d dps", data->gyro_fs);
408 }
409 #endif
410
411 err = inv_imu_set_accel_lp_avg(&data->driver,
412 (cfg->accel_avg << ACCEL_CONFIG1_ACCEL_UI_AVG_POS));
413 err |= inv_imu_set_accel_ln_bw(&data->driver,
414 (cfg->accel_filt_bw << ACCEL_CONFIG1_ACCEL_UI_FILT_BW_POS));
415 #if CONFIG_USE_EMD_ICM42670
416 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
417 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
418 err |= inv_imu_set_gyro_ln_bw(
419 &data->driver, (cfg->gyro_filt_bw << GYRO_CONFIG1_GYRO_UI_FILT_BW_POS));
420 }
421 #endif
422 if (err < 0) {
423 LOG_ERR("Failed to configure filtering.");
424 return -EIO;
425 }
426
427 if (cfg->accel_hz != 0) {
428 err |= inv_imu_set_accel_frequency(
429 &data->driver, cfg->accel_hz + ICM42X70_CONVERT_ENUM_TO_ODR_POS);
430 if ((cfg->accel_pwr_mode == ICM42X70_LOW_NOISE_MODE) &&
431 (convert_dt_enum_to_freq(cfg->accel_hz) >= 12)) {
432 err |= inv_imu_enable_accel_low_noise_mode(&data->driver);
433 } else if ((cfg->accel_pwr_mode == ICM42X70_LOW_POWER_MODE) &&
434 (convert_dt_enum_to_freq(cfg->accel_hz) <= 400)) {
435 err |= inv_imu_enable_accel_low_power_mode(&data->driver);
436 } else {
437 LOG_ERR("Not supported power mode value");
438 }
439 }
440 #if CONFIG_USE_EMD_ICM42670
441 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
442 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
443 if (cfg->gyro_hz != 0) {
444 err |= inv_imu_set_gyro_frequency(
445 &data->driver, cfg->gyro_hz + ICM42X70_CONVERT_ENUM_TO_ODR_POS);
446 err |= inv_imu_enable_gyro_low_noise_mode(&data->driver);
447 }
448 }
449 #endif
450 if (err < 0) {
451 LOG_ERR("Failed to configure ODR.");
452 return -EIO;
453 }
454
455 data->accel_pwr_mode = cfg->accel_pwr_mode;
456 data->accel_hz = convert_dt_enum_to_freq(cfg->accel_hz);
457 #if CONFIG_USE_EMD_ICM42670
458 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
459 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
460 data->gyro_hz = convert_dt_enum_to_freq(cfg->gyro_hz);
461 }
462 #endif
463
464 /*
465 * Accelerometer sensor need at least 10ms startup time
466 * Gyroscope sensor need at least 30ms startup time
467 */
468 k_msleep(100);
469
470 return 0;
471 }
472
icm42x70_convert_accel(struct sensor_value * val,int16_t raw_val,uint16_t fs)473 static void icm42x70_convert_accel(struct sensor_value *val, int16_t raw_val, uint16_t fs)
474 {
475 int64_t conv_val;
476
477 /* 16 bit accelerometer. 2^15 bits represent the range in G */
478 /* see datasheet section 3.2 for details */
479 conv_val = (int64_t)raw_val * SENSOR_G * fs / INT16_MAX;
480
481 val->val1 = conv_val / 1000000;
482 val->val2 = conv_val % 1000000;
483 }
484
icm42x70_convert_temp(struct sensor_value * val,int16_t raw_val)485 static void icm42x70_convert_temp(struct sensor_value *val, int16_t raw_val)
486 {
487 int64_t conv_val;
488
489 /* see datasheet section 15.9 for details */
490 conv_val = 25 * 1000000 + ((int64_t)raw_val * 1000000 / 2);
491 val->val1 = conv_val / 1000000;
492 val->val2 = conv_val % 1000000;
493 }
494
icm42x70_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)495 static int icm42x70_channel_get(const struct device *dev, enum sensor_channel chan,
496 struct sensor_value *val)
497 {
498 int res = 0;
499 struct icm42x70_data *data = dev->data;
500 #ifdef CONFIG_TDK_APEX
501 const struct icm42x70_config *cfg = dev->config;
502 #endif
503
504 icm42x70_lock(dev);
505
506 if (chan == SENSOR_CHAN_ACCEL_XYZ) {
507 icm42x70_convert_accel(&val[0], data->accel_x, data->accel_fs);
508 icm42x70_convert_accel(&val[1], data->accel_y, data->accel_fs);
509 icm42x70_convert_accel(&val[2], data->accel_z, data->accel_fs);
510 } else if (chan == SENSOR_CHAN_ACCEL_X) {
511 icm42x70_convert_accel(val, data->accel_x, data->accel_fs);
512 } else if (chan == SENSOR_CHAN_ACCEL_Y) {
513 icm42x70_convert_accel(val, data->accel_y, data->accel_fs);
514 } else if (chan == SENSOR_CHAN_ACCEL_Z) {
515 icm42x70_convert_accel(val, data->accel_z, data->accel_fs);
516 #if CONFIG_USE_EMD_ICM42670
517 } else if ((chan == SENSOR_CHAN_GYRO_XYZ) && ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
518 (data->imu_whoami == INV_ICM42670S_WHOAMI))) {
519 icm42670_convert_gyro(&val[0], data->gyro_x, data->gyro_fs);
520 icm42670_convert_gyro(&val[1], data->gyro_y, data->gyro_fs);
521 icm42670_convert_gyro(&val[2], data->gyro_z, data->gyro_fs);
522 } else if ((chan == SENSOR_CHAN_GYRO_X) && ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
523 (data->imu_whoami == INV_ICM42670S_WHOAMI))) {
524 icm42670_convert_gyro(val, data->gyro_x, data->gyro_fs);
525 } else if ((chan == SENSOR_CHAN_GYRO_Y) && ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
526 (data->imu_whoami == INV_ICM42670S_WHOAMI))) {
527 icm42670_convert_gyro(val, data->gyro_y, data->gyro_fs);
528 } else if ((chan == SENSOR_CHAN_GYRO_Z) && ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
529 (data->imu_whoami == INV_ICM42670S_WHOAMI))) {
530 icm42670_convert_gyro(val, data->gyro_z, data->gyro_fs);
531 #endif
532 } else if (chan == SENSOR_CHAN_DIE_TEMP) {
533 icm42x70_convert_temp(val, data->temp);
534 #ifdef CONFIG_TDK_APEX
535 } else if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) {
536 if (cfg->apex == TDK_APEX_PEDOMETER) {
537 val[0].val1 = data->pedometer_cnt;
538 val[1].val1 = data->pedometer_activity;
539 icm42x70_apex_pedometer_cadence_convert(&val[2], data->pedometer_cadence,
540 data->dmp_odr_hz);
541 } else if (cfg->apex == TDK_APEX_WOM) {
542 val[0].val1 = (data->apex_status & ICM42X70_APEX_STATUS_MASK_WOM_X) ? 1 : 0;
543 val[1].val1 = (data->apex_status & ICM42X70_APEX_STATUS_MASK_WOM_Y) ? 1 : 0;
544 val[2].val1 = (data->apex_status & ICM42X70_APEX_STATUS_MASK_WOM_Z) ? 1 : 0;
545 } else if ((cfg->apex == TDK_APEX_TILT) || (cfg->apex == TDK_APEX_SMD)) {
546 val[0].val1 = data->apex_status;
547 }
548 #endif
549 } else {
550 res = -ENOTSUP;
551 }
552
553 icm42x70_unlock(dev);
554
555 return res;
556 }
557
558 #ifdef CONFIG_ICM42X70_TRIGGER
icm42x70_fetch_from_fifo(const struct device * dev)559 static int icm42x70_fetch_from_fifo(const struct device *dev)
560 {
561 struct icm42x70_data *data = dev->data;
562 int status = 0;
563 uint8_t int_status;
564 uint16_t packet_size = FIFO_HEADER_SIZE + FIFO_ACCEL_DATA_SIZE + FIFO_GYRO_DATA_SIZE +
565 FIFO_TEMP_DATA_SIZE + FIFO_TS_FSYNC_SIZE;
566 uint16_t fifo_idx = 0;
567
568 /* Ensure data ready status bit is set */
569 status |= inv_imu_read_reg(&data->driver, INT_STATUS, 1, &int_status);
570 if (status != 0) {
571 return status;
572 }
573
574 if ((int_status & INT_STATUS_FIFO_THS_INT_MASK) ||
575 (int_status & INT_STATUS_FIFO_FULL_INT_MASK)) {
576 uint16_t packet_count;
577
578 /* Make sure RCOSC is enabled to guarrantee FIFO read */
579 status |= inv_imu_switch_on_mclk(&data->driver);
580
581 /* Read FIFO frame count */
582 status |= inv_imu_get_frame_count(&data->driver, &packet_count);
583
584 /* Check for error */
585 if (status != 0) {
586 status |= inv_imu_switch_off_mclk(&data->driver);
587 return status;
588 }
589
590 /* Read FIFO data */
591 status |= inv_imu_read_reg(&data->driver, FIFO_DATA, packet_size * packet_count,
592 (uint8_t *)&data->driver.fifo_data);
593
594 /* Check for error */
595 if (status != 0) {
596 status |= inv_imu_reset_fifo(&data->driver);
597 status |= inv_imu_switch_off_mclk(&data->driver);
598 return status;
599 }
600
601 for (uint16_t i = 0; i < packet_count; i++) {
602 inv_imu_sensor_event_t event;
603
604 status |= inv_imu_decode_fifo_frame(
605 &data->driver, &data->driver.fifo_data[fifo_idx], &event);
606 fifo_idx += packet_size;
607
608 /* Check for error */
609 if (status != 0) {
610 status |= inv_imu_reset_fifo(&data->driver);
611 status |= inv_imu_switch_off_mclk(&data->driver);
612 return status;
613 }
614
615 if (event.sensor_mask & (1 << INV_SENSOR_ACCEL)) {
616 data->accel_x = event.accel[0];
617 data->accel_y = event.accel[1];
618 data->accel_z = event.accel[2];
619 }
620 #if CONFIG_USE_EMD_ICM42670
621 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
622 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
623 if (event.sensor_mask & (1 << INV_SENSOR_GYRO)) {
624 data->gyro_x = event.gyro[0];
625 data->gyro_y = event.gyro[1];
626 data->gyro_z = event.gyro[2];
627 }
628 }
629 #endif
630 if (event.sensor_mask & (1 << INV_SENSOR_TEMPERATURE)) {
631 data->temp = event.temperature;
632 }
633 /*
634 * TODO use the sensor streaming interface with RTIO to handle multiple
635 * samples in FIFO
636 */
637
638 } /* end of FIFO read for loop */
639
640 status |= inv_imu_switch_off_mclk(&data->driver);
641 if (status < 0) {
642 return status;
643 }
644 } /*else: FIFO threshold was not reached and FIFO was not full */
645
646 return 0;
647 }
648 #endif
649
650 #ifndef CONFIG_ICM42X70_TRIGGER
icm42x70_sample_fetch_accel(const struct device * dev)651 static int icm42x70_sample_fetch_accel(const struct device *dev)
652 {
653 struct icm42x70_data *data = dev->data;
654 uint8_t buffer[ACCEL_DATA_SIZE];
655
656 int res = inv_imu_read_reg(&data->driver, ACCEL_DATA_X1, ACCEL_DATA_SIZE, buffer);
657
658 if (res) {
659 return res;
660 }
661
662 data->accel_x = (int16_t)sys_get_be16(&buffer[0]);
663 data->accel_y = (int16_t)sys_get_be16(&buffer[2]);
664 data->accel_z = (int16_t)sys_get_be16(&buffer[4]);
665
666 return 0;
667 }
668
icm42x70_sample_fetch_temp(const struct device * dev)669 static int icm42x70_sample_fetch_temp(const struct device *dev)
670 {
671 struct icm42x70_data *data = dev->data;
672 uint8_t buffer[TEMP_DATA_SIZE];
673
674 int res = inv_imu_read_reg(&data->driver, TEMP_DATA1, TEMP_DATA_SIZE, buffer);
675
676 if (res) {
677 return res;
678 }
679
680 data->temp = (int16_t)sys_get_be16(&buffer[0]);
681
682 return 0;
683 }
684
icm42x70_fetch_from_registers(const struct device * dev,enum sensor_channel chan)685 static int icm42x70_fetch_from_registers(const struct device *dev, enum sensor_channel chan)
686 {
687 struct icm42x70_data *data = dev->data;
688 int res = 0;
689 uint8_t int_status;
690
691 LOG_DBG("Fetch from reg");
692
693 icm42x70_lock(dev);
694
695 /* Ensure data ready status bit is set */
696 int err = inv_imu_read_reg(&data->driver, INT_STATUS_DRDY, 1, &int_status);
697
698 if (int_status & INT_STATUS_DRDY_DATA_RDY_INT_MASK) {
699 switch (chan) {
700 case SENSOR_CHAN_ALL:
701 err |= icm42x70_sample_fetch_accel(dev);
702 #if CONFIG_USE_EMD_ICM42670
703 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
704 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
705 err |= icm42670_sample_fetch_gyro(dev);
706 }
707 #endif
708 err |= icm42x70_sample_fetch_temp(dev);
709 break;
710 case SENSOR_CHAN_ACCEL_XYZ:
711 case SENSOR_CHAN_ACCEL_X:
712 case SENSOR_CHAN_ACCEL_Y:
713 case SENSOR_CHAN_ACCEL_Z:
714 err |= icm42x70_sample_fetch_accel(dev);
715 break;
716 #if CONFIG_USE_EMD_ICM42670
717 case SENSOR_CHAN_GYRO_XYZ:
718 case SENSOR_CHAN_GYRO_X:
719 case SENSOR_CHAN_GYRO_Y:
720 case SENSOR_CHAN_GYRO_Z:
721 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
722 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
723 err |= icm42670_sample_fetch_gyro(dev);
724 } else {
725 res = -ENOTSUP;
726 }
727 break;
728 #endif
729 case SENSOR_CHAN_DIE_TEMP:
730 err |= icm42x70_sample_fetch_temp(dev);
731 break;
732 default:
733 res = -ENOTSUP;
734 break;
735 }
736 }
737
738 icm42x70_unlock(dev);
739
740 if (err < 0) {
741 res = -EIO;
742 }
743 return res;
744 }
745 #endif
746
icm42x70_sample_fetch(const struct device * dev,enum sensor_channel chan)747 static int icm42x70_sample_fetch(const struct device *dev, enum sensor_channel chan)
748 {
749 #if CONFIG_USE_EMD_ICM42670
750 struct icm42x70_data *data = dev->data;
751 #endif
752 int status = -ENOTSUP;
753
754 icm42x70_lock(dev);
755
756 #ifdef CONFIG_TDK_APEX
757 if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) {
758 status = icm42x70_apex_fetch_from_dmp(dev);
759 }
760 #endif
761
762 if ((chan == SENSOR_CHAN_ALL) || SENSOR_CHANNEL_IS_ACCEL(chan) ||
763 #if CONFIG_USE_EMD_ICM42670
764 (SENSOR_CHANNEL_IS_GYRO(chan) && ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
765 (data->imu_whoami == INV_ICM42670S_WHOAMI))) ||
766 #endif
767 (chan == SENSOR_CHAN_DIE_TEMP)) {
768 #ifdef CONFIG_ICM42X70_TRIGGER
769 status = icm42x70_fetch_from_fifo(dev);
770 #else
771 status = icm42x70_fetch_from_registers(dev, chan);
772 #endif
773 }
774
775 icm42x70_unlock(dev);
776 return status;
777 }
778
icm42x70_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)779 static int icm42x70_attr_set(const struct device *dev, enum sensor_channel chan,
780 enum sensor_attribute attr, const struct sensor_value *val)
781 {
782 struct icm42x70_data *drv_data = dev->data;
783
784 __ASSERT_NO_MSG(val != NULL);
785
786 icm42x70_lock(dev);
787
788 if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) {
789 if (attr == SENSOR_ATTR_CONFIGURATION) {
790 #ifdef CONFIG_TDK_APEX
791 if (val->val1 == TDK_APEX_PEDOMETER) {
792 icm42x70_apex_enable(&drv_data->driver);
793 icm42x70_apex_enable_pedometer(dev, &drv_data->driver);
794 } else if (val->val1 == TDK_APEX_TILT) {
795 icm42x70_apex_enable(&drv_data->driver);
796 icm42x70_apex_enable_tilt(&drv_data->driver);
797 } else if (val->val1 == TDK_APEX_SMD) {
798 icm42x70_apex_enable(&drv_data->driver);
799 icm42x70_apex_enable_smd(&drv_data->driver);
800 } else if (val->val1 == TDK_APEX_WOM) {
801 icm42x70_apex_enable_wom(&drv_data->driver);
802 } else {
803 LOG_ERR("Not supported ATTR value");
804 }
805 #endif
806 } else {
807 LOG_ERR("Not supported ATTR");
808 return -EINVAL;
809 }
810 } else if (SENSOR_CHANNEL_IS_ACCEL(chan)) {
811 icm42x70_accel_config(drv_data, attr, val);
812 #if CONFIG_USE_EMD_ICM42670
813 } else if ((SENSOR_CHANNEL_IS_GYRO(chan)) &&
814 ((drv_data->imu_whoami == INV_ICM42670P_WHOAMI) ||
815 (drv_data->imu_whoami == INV_ICM42670S_WHOAMI))) {
816 icm42670_gyro_config(drv_data, attr, val);
817 #endif
818 } else {
819 LOG_ERR("Unsupported channel");
820 (void)drv_data;
821 return -EINVAL;
822 }
823
824 icm42x70_unlock(dev);
825
826 return 0;
827 }
828
icm42x70_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)829 static int icm42x70_attr_get(const struct device *dev, enum sensor_channel chan,
830 enum sensor_attribute attr, struct sensor_value *val)
831 {
832 const struct icm42x70_data *data = dev->data;
833 const struct icm42x70_config *cfg = dev->config;
834 int res = 0;
835
836 __ASSERT_NO_MSG(val != NULL);
837
838 icm42x70_lock(dev);
839
840 switch (chan) {
841 case SENSOR_CHAN_ACCEL_X:
842 case SENSOR_CHAN_ACCEL_Y:
843 case SENSOR_CHAN_ACCEL_Z:
844 case SENSOR_CHAN_ACCEL_XYZ:
845 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
846 val->val1 = data->accel_hz;
847 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
848 val->val1 = data->accel_fs;
849 } else {
850 LOG_ERR("Unsupported attribute");
851 res = -EINVAL;
852 }
853 break;
854 #if CONFIG_USE_EMD_ICM42670
855 case SENSOR_CHAN_GYRO_X:
856 case SENSOR_CHAN_GYRO_Y:
857 case SENSOR_CHAN_GYRO_Z:
858 case SENSOR_CHAN_GYRO_XYZ:
859 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
860 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
861 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
862 val->val1 = data->gyro_hz;
863 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
864 val->val1 = data->gyro_fs;
865 } else {
866 LOG_ERR("Unsupported attribute");
867 res = -EINVAL;
868 }
869 } else {
870 res = -EINVAL;
871 }
872 break;
873 #endif
874 case SENSOR_CHAN_APEX_MOTION:
875 if (attr == SENSOR_ATTR_CONFIGURATION) {
876 val->val1 = cfg->apex;
877 }
878 break;
879
880 default:
881 LOG_ERR("Unsupported channel");
882 res = -EINVAL;
883 break;
884 }
885
886 icm42x70_unlock(dev);
887
888 return res;
889 }
890
icm42x70_bus_check(const struct device * dev)891 static inline int icm42x70_bus_check(const struct device *dev)
892 {
893 const struct icm42x70_config *cfg = dev->config;
894
895 return cfg->bus_io->check(&cfg->bus);
896 }
897
icm42x70_init(const struct device * dev)898 static int icm42x70_init(const struct device *dev)
899 {
900 struct icm42x70_data *data = dev->data;
901 int res = 0;
902
903 if (icm42x70_bus_check(dev) < 0) {
904 LOG_ERR("bus check failed");
905 return -ENODEV;
906 }
907
908 data->accel_x = 0;
909 data->accel_y = 0;
910 data->accel_z = 0;
911 #if CONFIG_USE_EMD_ICM42670
912 if ((data->imu_whoami == INV_ICM42670P_WHOAMI) ||
913 (data->imu_whoami == INV_ICM42670S_WHOAMI)) {
914 data->gyro_x = 0;
915 data->gyro_y = 0;
916 data->gyro_z = 0;
917 }
918 #endif
919 data->temp = 0;
920
921 if (icm42x70_sensor_init(dev)) {
922 LOG_ERR("could not initialize sensor");
923 return -EIO;
924 }
925
926 #ifdef CONFIG_ICM42X70_TRIGGER
927 res |= icm42x70_trigger_enable_interrupt(dev);
928 res |= icm42x70_trigger_init(dev);
929 if (res < 0) {
930 LOG_ERR("Failed to initialize interrupt.");
931 return res;
932 }
933 #endif
934
935 res |= icm42x70_turn_on_sensor(dev);
936
937 return res;
938 }
939
940 #ifndef CONFIG_ICM42X70_TRIGGER
941
icm42x70_lock(const struct device * dev)942 void icm42x70_lock(const struct device *dev)
943 {
944 ARG_UNUSED(dev);
945 }
946
icm42x70_unlock(const struct device * dev)947 void icm42x70_unlock(const struct device *dev)
948 {
949 ARG_UNUSED(dev);
950 }
951
952 #endif
953
954 static DEVICE_API(sensor, icm42x70_driver_api) = {
955 #ifdef CONFIG_ICM42X70_TRIGGER
956 .trigger_set = icm42x70_trigger_set,
957 #endif
958 .sample_fetch = icm42x70_sample_fetch,
959 .channel_get = icm42x70_channel_get,
960 .attr_set = icm42x70_attr_set,
961 .attr_get = icm42x70_attr_get,
962 };
963
964 /* device defaults to spi mode 0/3 support */
965 #define ICM42X70_SPI_CFG (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA)
966
967 /* Initializes a common struct icm42x70_config */
968 #define ICM42X70_CONFIG_COMMON(inst) \
969 IF_ENABLED(CONFIG_ICM42X70_TRIGGER, \
970 (.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}),)) \
971 .accel_fs = DT_INST_ENUM_IDX(inst, accel_fs), \
972 .accel_hz = DT_INST_ENUM_IDX(inst, accel_hz), \
973 .accel_avg = DT_INST_ENUM_IDX(inst, accel_avg), \
974 .accel_filt_bw = DT_INST_ENUM_IDX(inst, accel_filt_bw_hz), \
975 .accel_pwr_mode = DT_INST_ENUM_IDX(inst, power_mode), \
976 .apex = DT_INST_ENUM_IDX(inst, apex), \
977 .accel_pwr_mode = DT_INST_ENUM_IDX(inst, power_mode), \
978 .apex = DT_INST_ENUM_IDX(inst, apex), \
979 IF_ENABLED(CONFIG_USE_EMD_ICM42670, \
980 (.gyro_fs = DT_INST_ENUM_IDX(inst, gyro_fs),)) \
981 IF_ENABLED(CONFIG_USE_EMD_ICM42670, \
982 (.gyro_hz = DT_INST_ENUM_IDX(inst, gyro_hz),)) \
983 IF_ENABLED(CONFIG_USE_EMD_ICM42670, \
984 (.gyro_filt_bw = DT_INST_ENUM_IDX(inst, gyro_filt_bw_hz),))
985
986 /* Initializes the bus members for an instance on a SPI bus. */
987 #define ICM42X70_CONFIG_SPI(inst) \
988 {.bus.spi = SPI_DT_SPEC_INST_GET(inst, ICM42X70_SPI_CFG, 0), \
989 .bus_io = &icm42x70_bus_io_spi, \
990 .serif_type = UI_SPI4, \
991 ICM42X70_CONFIG_COMMON(inst)}
992
993 /* Initializes the bus members for an instance on an I2C bus. */
994 #define ICM42X70_CONFIG_I2C(inst) \
995 {.bus.i2c = I2C_DT_SPEC_INST_GET(inst), \
996 .bus_io = &icm42x70_bus_io_i2c, \
997 .serif_type = UI_I2C, \
998 ICM42X70_CONFIG_COMMON(inst)}
999
1000 /*
1001 * Main instantiation macro, which selects the correct bus-specific
1002 * instantiation macros for the instance.
1003 */
1004 #define ICM42X70_DEFINE(inst, name, whoami) \
1005 static struct icm42x70_data icm42x70_data_##inst = { \
1006 .imu_name = name, \
1007 .imu_whoami = whoami, \
1008 }; \
1009 static const struct icm42x70_config icm42x70_config_##inst = \
1010 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
1011 (ICM42X70_CONFIG_SPI(inst)), \
1012 (ICM42X70_CONFIG_I2C(inst))); \
1013 SENSOR_DEVICE_DT_INST_DEFINE(inst, icm42x70_init, NULL, &icm42x70_data_##inst, \
1014 &icm42x70_config_##inst, POST_KERNEL, \
1015 CONFIG_SENSOR_INIT_PRIORITY, &icm42x70_driver_api);
1016
1017 #define DT_DRV_COMPAT invensense_icm42670p
1018 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
1019 DT_INST_FOREACH_STATUS_OKAY_VARGS(ICM42X70_DEFINE, INV_ICM42670P_STRING_ID, INV_ICM42670P_WHOAMI);
1020 #endif
1021 #undef DT_DRV_COMPAT
1022
1023 #define DT_DRV_COMPAT invensense_icm42670s
1024 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
1025 DT_INST_FOREACH_STATUS_OKAY_VARGS(ICM42X70_DEFINE, INV_ICM42670S_STRING_ID, INV_ICM42670S_WHOAMI);
1026 #endif
1027 #undef DT_DRV_COMPAT
1028
1029 #define DT_DRV_COMPAT invensense_icm42370p
1030 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
1031 DT_INST_FOREACH_STATUS_OKAY_VARGS(ICM42X70_DEFINE, INV_ICM42370P_STRING_ID, INV_ICM42370P_WHOAMI);
1032 #endif
1033