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