1 /*
2 * Copyright (c) 2020 TDK Invensense
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT invensense_icm42605
8
9 #include <zephyr/drivers/spi.h>
10 #include <zephyr/init.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/logging/log.h>
14
15 #include "icm42605.h"
16 #include "icm42605_reg.h"
17 #include "icm42605_setup.h"
18 #include "icm42605_spi.h"
19
20 LOG_MODULE_REGISTER(ICM42605, CONFIG_SENSOR_LOG_LEVEL);
21
22 static const uint16_t icm42605_gyro_sensitivity_x10[] = {
23 1310, 655, 328, 164
24 };
25
26 /* see "Accelerometer Measurements" section from register map description */
icm42605_convert_accel(struct sensor_value * val,int16_t raw_val,uint16_t sensitivity_shift)27 static void icm42605_convert_accel(struct sensor_value *val,
28 int16_t raw_val,
29 uint16_t sensitivity_shift)
30 {
31 int64_t conv_val;
32
33 conv_val = ((int64_t)raw_val * SENSOR_G) >> sensitivity_shift;
34 val->val1 = conv_val / 1000000;
35 val->val2 = conv_val % 1000000;
36 }
37
38 /* see "Gyroscope Measurements" section from register map description */
icm42605_convert_gyro(struct sensor_value * val,int16_t raw_val,uint16_t sensitivity_x10)39 static void icm42605_convert_gyro(struct sensor_value *val,
40 int16_t raw_val,
41 uint16_t sensitivity_x10)
42 {
43 int64_t conv_val;
44
45 conv_val = ((int64_t)raw_val * SENSOR_PI * 10) /
46 (sensitivity_x10 * 180U);
47 val->val1 = conv_val / 1000000;
48 val->val2 = conv_val % 1000000;
49 }
50
51 /* see "Temperature Measurement" section from register map description */
icm42605_convert_temp(struct sensor_value * val,int16_t raw_val)52 static inline void icm42605_convert_temp(struct sensor_value *val,
53 int16_t raw_val)
54 {
55 val->val1 = (((int64_t)raw_val * 100) / 207) + 25;
56 val->val2 = ((((int64_t)raw_val * 100) % 207) * 1000000) / 207;
57
58 if (val->val2 < 0) {
59 val->val1--;
60 val->val2 += 1000000;
61 } else if (val->val2 >= 1000000) {
62 val->val1++;
63 val->val2 -= 1000000;
64 }
65 }
66
icm42605_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)67 static int icm42605_channel_get(const struct device *dev,
68 enum sensor_channel chan,
69 struct sensor_value *val)
70 {
71 const struct icm42605_data *drv_data = dev->data;
72
73 switch (chan) {
74 case SENSOR_CHAN_ACCEL_XYZ:
75 icm42605_convert_accel(val, drv_data->accel_x,
76 drv_data->accel_sensitivity_shift);
77 icm42605_convert_accel(val + 1, drv_data->accel_y,
78 drv_data->accel_sensitivity_shift);
79 icm42605_convert_accel(val + 2, drv_data->accel_z,
80 drv_data->accel_sensitivity_shift);
81 break;
82 case SENSOR_CHAN_ACCEL_X:
83 icm42605_convert_accel(val, drv_data->accel_x,
84 drv_data->accel_sensitivity_shift);
85 break;
86 case SENSOR_CHAN_ACCEL_Y:
87 icm42605_convert_accel(val, drv_data->accel_y,
88 drv_data->accel_sensitivity_shift);
89 break;
90 case SENSOR_CHAN_ACCEL_Z:
91 icm42605_convert_accel(val, drv_data->accel_z,
92 drv_data->accel_sensitivity_shift);
93 break;
94 case SENSOR_CHAN_GYRO_XYZ:
95 icm42605_convert_gyro(val, drv_data->gyro_x,
96 drv_data->gyro_sensitivity_x10);
97 icm42605_convert_gyro(val + 1, drv_data->gyro_y,
98 drv_data->gyro_sensitivity_x10);
99 icm42605_convert_gyro(val + 2, drv_data->gyro_z,
100 drv_data->gyro_sensitivity_x10);
101 break;
102 case SENSOR_CHAN_GYRO_X:
103 icm42605_convert_gyro(val, drv_data->gyro_x,
104 drv_data->gyro_sensitivity_x10);
105 break;
106 case SENSOR_CHAN_GYRO_Y:
107 icm42605_convert_gyro(val, drv_data->gyro_y,
108 drv_data->gyro_sensitivity_x10);
109 break;
110 case SENSOR_CHAN_GYRO_Z:
111 icm42605_convert_gyro(val, drv_data->gyro_z,
112 drv_data->gyro_sensitivity_x10);
113 break;
114 case SENSOR_CHAN_DIE_TEMP:
115 icm42605_convert_temp(val, drv_data->temp);
116 break;
117 default:
118 return -ENOTSUP;
119 }
120
121 return 0;
122 }
123
icm42605_tap_fetch(const struct device * dev)124 int icm42605_tap_fetch(const struct device *dev)
125 {
126 int result = 0;
127 struct icm42605_data *drv_data = dev->data;
128 const struct icm42605_config *cfg = dev->config;
129
130 if (drv_data->tap_en &&
131 (drv_data->tap_handler || drv_data->double_tap_handler)) {
132 result = inv_spi_read(&cfg->spi, REG_INT_STATUS3, drv_data->fifo_data, 1);
133 if (drv_data->fifo_data[0] & BIT_INT_STATUS_TAP_DET) {
134 result = inv_spi_read(&cfg->spi, REG_APEX_DATA4,
135 drv_data->fifo_data, 1);
136 if (drv_data->fifo_data[0] & APEX_TAP) {
137 if (drv_data->tap_trigger->type ==
138 SENSOR_TRIG_TAP) {
139 if (drv_data->tap_handler) {
140 LOG_DBG("Single Tap detected");
141 drv_data->tap_handler(dev
142 , drv_data->tap_trigger);
143 }
144 } else {
145 LOG_ERR("Trigger type is mismatched");
146 }
147 } else if (drv_data->fifo_data[0] & APEX_DOUBLE_TAP) {
148 if (drv_data->double_tap_trigger->type ==
149 SENSOR_TRIG_DOUBLE_TAP) {
150 if (drv_data->double_tap_handler) {
151 LOG_DBG("Double Tap detected");
152 drv_data->double_tap_handler(dev
153 , drv_data->tap_trigger);
154 }
155 } else {
156 LOG_ERR("Trigger type is mismatched");
157 }
158 } else {
159 LOG_DBG("Not supported tap event");
160 }
161 }
162 }
163
164 return 0;
165 }
166
icm42605_sample_fetch(const struct device * dev,enum sensor_channel chan)167 static int icm42605_sample_fetch(const struct device *dev,
168 enum sensor_channel chan)
169 {
170 int result = 0;
171 uint16_t fifo_count = 0;
172 struct icm42605_data *drv_data = dev->data;
173 const struct icm42605_config *cfg = dev->config;
174
175 /* Read INT_STATUS (0x45) and FIFO_COUNTH(0x46), FIFO_COUNTL(0x47) */
176 result = inv_spi_read(&cfg->spi, REG_INT_STATUS, drv_data->fifo_data, 3);
177
178 if (drv_data->fifo_data[0] & BIT_INT_STATUS_DRDY) {
179 fifo_count = (drv_data->fifo_data[1] << 8)
180 + (drv_data->fifo_data[2]);
181 result = inv_spi_read(&cfg->spi, REG_FIFO_DATA, drv_data->fifo_data,
182 fifo_count);
183
184 /* FIFO Data structure
185 * Packet 1 : FIFO Header(1), AccelX(2), AccelY(2),
186 * AccelZ(2), Temperature(1)
187 * Packet 2 : FIFO Header(1), GyroX(2), GyroY(2),
188 * GyroZ(2), Temperature(1)
189 * Packet 3 : FIFO Header(1), AccelX(2), AccelY(2), AccelZ(2),
190 * GyroX(2), GyroY(2), GyroZ(2), Temperature(1)
191 */
192 if (drv_data->fifo_data[0] & BIT_FIFO_HEAD_ACCEL) {
193 /* Check empty values */
194 if (!(drv_data->fifo_data[1] == FIFO_ACCEL0_RESET_VALUE
195 && drv_data->fifo_data[2] ==
196 FIFO_ACCEL1_RESET_VALUE)) {
197 drv_data->accel_x =
198 (drv_data->fifo_data[1] << 8)
199 + (drv_data->fifo_data[2]);
200 drv_data->accel_y =
201 (drv_data->fifo_data[3] << 8)
202 + (drv_data->fifo_data[4]);
203 drv_data->accel_z =
204 (drv_data->fifo_data[5] << 8)
205 + (drv_data->fifo_data[6]);
206 }
207 if (!(drv_data->fifo_data[0] & BIT_FIFO_HEAD_GYRO)) {
208 drv_data->temp =
209 (int16_t)(drv_data->fifo_data[7]);
210 } else {
211 if (!(drv_data->fifo_data[7] ==
212 FIFO_GYRO0_RESET_VALUE &&
213 drv_data->fifo_data[8] ==
214 FIFO_GYRO1_RESET_VALUE)) {
215 drv_data->gyro_x =
216 (drv_data->fifo_data[7] << 8)
217 + (drv_data->fifo_data[8]);
218 drv_data->gyro_y =
219 (drv_data->fifo_data[9] << 8)
220 + (drv_data->fifo_data[10]);
221 drv_data->gyro_z =
222 (drv_data->fifo_data[11] << 8)
223 + (drv_data->fifo_data[12]);
224 }
225 drv_data->temp =
226 (int16_t)(drv_data->fifo_data[13]);
227 }
228 } else {
229 if (drv_data->fifo_data[0] & BIT_FIFO_HEAD_GYRO) {
230 if (!(drv_data->fifo_data[1] ==
231 FIFO_GYRO0_RESET_VALUE &&
232 drv_data->fifo_data[2] ==
233 FIFO_GYRO1_RESET_VALUE)) {
234 drv_data->gyro_x =
235 (drv_data->fifo_data[1] << 8)
236 + (drv_data->fifo_data[2]);
237 drv_data->gyro_y =
238 (drv_data->fifo_data[3] << 8)
239 + (drv_data->fifo_data[4]);
240 drv_data->gyro_z =
241 (drv_data->fifo_data[5] << 8)
242 + (drv_data->fifo_data[6]);
243 }
244 drv_data->temp =
245 (int16_t)(drv_data->fifo_data[7]);
246 }
247 }
248 }
249
250 return 0;
251 }
252
icm42605_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)253 static int icm42605_attr_set(const struct device *dev,
254 enum sensor_channel chan,
255 enum sensor_attribute attr,
256 const struct sensor_value *val)
257 {
258 struct icm42605_data *drv_data = dev->data;
259
260 __ASSERT_NO_MSG(val != NULL);
261
262 switch (chan) {
263 case SENSOR_CHAN_ACCEL_X:
264 case SENSOR_CHAN_ACCEL_Y:
265 case SENSOR_CHAN_ACCEL_Z:
266 case SENSOR_CHAN_ACCEL_XYZ:
267 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
268 if (val->val1 > 8000 || val->val1 < 1) {
269 LOG_ERR("Incorrect sampling value");
270 return -EINVAL;
271 } else {
272 drv_data->accel_hz = val->val1;
273 }
274 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
275 if (val->val1 < ACCEL_FS_16G ||
276 val->val1 > ACCEL_FS_2G) {
277 LOG_ERR("Incorrect fullscale value");
278 return -EINVAL;
279 } else {
280 drv_data->accel_sf = val->val1;
281 }
282 } else {
283 LOG_ERR("Not supported ATTR");
284 return -ENOTSUP;
285 }
286
287 break;
288 case SENSOR_CHAN_GYRO_X:
289 case SENSOR_CHAN_GYRO_Y:
290 case SENSOR_CHAN_GYRO_Z:
291 case SENSOR_CHAN_GYRO_XYZ:
292 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
293 if (val->val1 > 8000 || val->val1 < 12) {
294 LOG_ERR("Incorrect sampling value");
295 return -EINVAL;
296 } else {
297 drv_data->gyro_hz = val->val1;
298 }
299 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
300 if (val->val1 < GYRO_FS_2000DPS ||
301 val->val1 > GYRO_FS_15DPS) {
302 LOG_ERR("Incorrect fullscale value");
303 return -EINVAL;
304 } else {
305 drv_data->gyro_sf = val->val1;
306 }
307 } else {
308 LOG_ERR("Not supported ATTR");
309 return -EINVAL;
310 }
311 break;
312 default:
313 LOG_ERR("Not support");
314 return -EINVAL;
315 }
316
317 return 0;
318 }
319
icm42605_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)320 static int icm42605_attr_get(const struct device *dev,
321 enum sensor_channel chan,
322 enum sensor_attribute attr,
323 struct sensor_value *val)
324 {
325 const struct icm42605_data *drv_data = dev->data;
326
327 __ASSERT_NO_MSG(val != NULL);
328
329 switch (chan) {
330 case SENSOR_CHAN_ACCEL_X:
331 case SENSOR_CHAN_ACCEL_Y:
332 case SENSOR_CHAN_ACCEL_Z:
333 case SENSOR_CHAN_ACCEL_XYZ:
334 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
335 val->val1 = drv_data->accel_hz;
336 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
337 val->val1 = drv_data->accel_sf;
338 } else {
339 LOG_ERR("Not supported ATTR");
340 return -EINVAL;
341 }
342
343 break;
344 case SENSOR_CHAN_GYRO_X:
345 case SENSOR_CHAN_GYRO_Y:
346 case SENSOR_CHAN_GYRO_Z:
347 case SENSOR_CHAN_GYRO_XYZ:
348 if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
349 val->val1 = drv_data->gyro_hz;
350 } else if (attr == SENSOR_ATTR_FULL_SCALE) {
351 val->val1 = drv_data->gyro_sf;
352 } else {
353 LOG_ERR("Not supported ATTR");
354 return -EINVAL;
355 }
356
357 break;
358
359 default:
360 LOG_ERR("Not support");
361 return -EINVAL;
362 }
363
364 return 0;
365 }
366
icm42605_data_init(struct icm42605_data * data,const struct icm42605_config * cfg)367 static int icm42605_data_init(struct icm42605_data *data,
368 const struct icm42605_config *cfg)
369 {
370 data->accel_x = 0;
371 data->accel_y = 0;
372 data->accel_z = 0;
373 data->temp = 0;
374 data->gyro_x = 0;
375 data->gyro_y = 0;
376 data->gyro_z = 0;
377 data->accel_hz = cfg->accel_hz;
378 data->gyro_hz = cfg->gyro_hz;
379
380 data->accel_sf = cfg->accel_fs;
381 data->gyro_sf = cfg->gyro_fs;
382
383 data->tap_en = false;
384 data->sensor_started = false;
385
386 return 0;
387 }
388
389
icm42605_init(const struct device * dev)390 static int icm42605_init(const struct device *dev)
391 {
392 struct icm42605_data *drv_data = dev->data;
393 const struct icm42605_config *cfg = dev->config;
394
395 if (!spi_is_ready_dt(&cfg->spi)) {
396 LOG_ERR("SPI bus is not ready");
397 return -ENODEV;
398 }
399
400 icm42605_data_init(drv_data, cfg);
401 icm42605_sensor_init(dev);
402
403 drv_data->accel_sensitivity_shift = 14 - 3;
404 drv_data->gyro_sensitivity_x10 = icm42605_gyro_sensitivity_x10[3];
405
406 #ifdef CONFIG_ICM42605_TRIGGER
407 if (icm42605_init_interrupt(dev) < 0) {
408 LOG_ERR("Failed to initialize interrupts.");
409 return -EIO;
410 }
411 #endif
412
413 LOG_DBG("Initialize interrupt done");
414
415 return 0;
416 }
417
418 static DEVICE_API(sensor, icm42605_driver_api) = {
419 #ifdef CONFIG_ICM42605_TRIGGER
420 .trigger_set = icm42605_trigger_set,
421 #endif
422 .sample_fetch = icm42605_sample_fetch,
423 .channel_get = icm42605_channel_get,
424 .attr_set = icm42605_attr_set,
425 .attr_get = icm42605_attr_get,
426 };
427
428 #define ICM42605_DEFINE_CONFIG(index) \
429 static const struct icm42605_config icm42605_cfg_##index = { \
430 .spi = SPI_DT_SPEC_INST_GET(index, \
431 SPI_OP_MODE_MASTER | \
432 SPI_MODE_CPOL | \
433 SPI_MODE_CPHA | \
434 SPI_WORD_SET(8) | \
435 SPI_TRANSFER_MSB, \
436 0U), \
437 .gpio_int = GPIO_DT_SPEC_INST_GET(index, int_gpios), \
438 .accel_hz = DT_INST_PROP(index, accel_hz), \
439 .gyro_hz = DT_INST_PROP(index, gyro_hz), \
440 .accel_fs = DT_INST_ENUM_IDX(index, accel_fs), \
441 .gyro_fs = DT_INST_ENUM_IDX(index, gyro_fs), \
442 }
443
444 #define ICM42605_INIT(index) \
445 ICM42605_DEFINE_CONFIG(index); \
446 static struct icm42605_data icm42605_driver_##index; \
447 SENSOR_DEVICE_DT_INST_DEFINE(index, icm42605_init, \
448 NULL, \
449 &icm42605_driver_##index, \
450 &icm42605_cfg_##index, POST_KERNEL, \
451 CONFIG_SENSOR_INIT_PRIORITY, \
452 &icm42605_driver_api);
453
454 DT_INST_FOREACH_STATUS_OKAY(ICM42605_INIT)
455