1 /* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver
2  *
3  * Copyright (c) 2023 Google LLC
4  * Copyright (c) 2024 STMicroelectronics
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include "lsm6dsv16x.h"
10 #include "lsm6dsv16x_decoder.h"
11 #include <zephyr/dt-bindings/sensor/lsm6dsv16x.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(LSM6DSV16X_DECODER, CONFIG_SENSOR_LOG_LEVEL);
15 
16 #ifdef CONFIG_LSM6DSV16X_STREAM
17 static const uint32_t accel_period_ns[] = {
18 	[LSM6DSV16X_XL_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875,
19 	[LSM6DSV16X_XL_BATCHED_AT_7Hz5] = UINT32_C(1000000000000) / 7500,
20 	[LSM6DSV16X_XL_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15,
21 	[LSM6DSV16X_XL_BATCHED_AT_30Hz] = UINT32_C(1000000000) / 30,
22 	[LSM6DSV16X_XL_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60,
23 	[LSM6DSV16X_XL_BATCHED_AT_120Hz] = UINT32_C(1000000000) / 120,
24 	[LSM6DSV16X_XL_BATCHED_AT_240Hz] = UINT32_C(1000000000) / 240,
25 	[LSM6DSV16X_XL_BATCHED_AT_480Hz] = UINT32_C(1000000000) / 480,
26 	[LSM6DSV16X_XL_BATCHED_AT_960Hz] = UINT32_C(1000000000) / 960,
27 	[LSM6DSV16X_XL_BATCHED_AT_1920Hz] = UINT32_C(1000000000) / 1920,
28 	[LSM6DSV16X_XL_BATCHED_AT_3840Hz] = UINT32_C(1000000000) / 3840,
29 	[LSM6DSV16X_XL_BATCHED_AT_7680Hz] = UINT32_C(1000000000) / 7680,
30 };
31 
32 static const uint32_t gyro_period_ns[] = {
33 	[LSM6DSV16X_GY_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875,
34 	[LSM6DSV16X_GY_BATCHED_AT_7Hz5] = UINT32_C(1000000000000) / 7500,
35 	[LSM6DSV16X_GY_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15,
36 	[LSM6DSV16X_GY_BATCHED_AT_30Hz] = UINT32_C(1000000000) / 30,
37 	[LSM6DSV16X_GY_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60,
38 	[LSM6DSV16X_GY_BATCHED_AT_120Hz] = UINT32_C(1000000000) / 120,
39 	[LSM6DSV16X_GY_BATCHED_AT_240Hz] = UINT32_C(1000000000) / 240,
40 	[LSM6DSV16X_GY_BATCHED_AT_480Hz] = UINT32_C(1000000000) / 480,
41 	[LSM6DSV16X_GY_BATCHED_AT_960Hz] = UINT32_C(1000000000) / 960,
42 	[LSM6DSV16X_GY_BATCHED_AT_1920Hz] = UINT32_C(1000000000) / 1920,
43 	[LSM6DSV16X_GY_BATCHED_AT_3840Hz] = UINT32_C(1000000000) / 3840,
44 	[LSM6DSV16X_GY_BATCHED_AT_7680Hz] = UINT32_C(1000000000) / 7680,
45 };
46 
47 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
48 static const uint32_t temp_period_ns[] = {
49 	[LSM6DSV16X_TEMP_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875,
50 	[LSM6DSV16X_TEMP_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15,
51 	[LSM6DSV16X_TEMP_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60,
52 };
53 #endif
54 
55 static const uint32_t sflp_period_ns[] = {
56 	[LSM6DSV16X_DT_SFLP_ODR_AT_15Hz] = UINT32_C(1000000000) / 15,
57 	[LSM6DSV16X_DT_SFLP_ODR_AT_30Hz] = UINT32_C(1000000000) / 30,
58 	[LSM6DSV16X_DT_SFLP_ODR_AT_60Hz] = UINT32_C(1000000000) / 60,
59 	[LSM6DSV16X_DT_SFLP_ODR_AT_120Hz] = UINT32_C(1000000000) / 120,
60 	[LSM6DSV16X_DT_SFLP_ODR_AT_240Hz] = UINT32_C(1000000000) / 240,
61 	[LSM6DSV16X_DT_SFLP_ODR_AT_480Hz] = UINT32_C(1000000000) / 480,
62 };
63 #endif /* CONFIG_LSM6DSV16X_STREAM */
64 
65 /*
66  * Expand val to q31_t according to its range; this is achieved multiplying by 2^31/2^range.
67  */
68 #define Q31_SHIFT_VAL(val, range) \
69 	(q31_t) (round((val) * ((int64_t)1 << (31 - (range)))))
70 
71 /*
72  * Expand micro_val (a generic micro unit) to q31_t according to its range; this is achieved
73  * multiplying by 2^31/2^range. Then transform it to val.
74  */
75 #define Q31_SHIFT_MICROVAL(micro_val, range) \
76 	(q31_t) ((int64_t)(micro_val) * ((int64_t)1 << (31 - (range))) / 1000000LL)
77 
78 /* bit range for Accelerometer for a given fs */
79 static const int8_t accel_range[] = {
80 	[LSM6DSV16X_DT_FS_2G] = 5,
81 	[LSM6DSV16X_DT_FS_4G] = 6,
82 	[LSM6DSV16X_DT_FS_8G] = 7,
83 	[LSM6DSV16X_DT_FS_16G] = 8,
84 };
85 
86 /* bit range for Gyroscope for a given fs */
87 static const int8_t gyro_range[] = {
88 	[LSM6DSV16X_DT_FS_125DPS] = 2,
89 	[LSM6DSV16X_DT_FS_250DPS] = 3,
90 	[LSM6DSV16X_DT_FS_500DPS] = 4,
91 	[LSM6DSV16X_DT_FS_1000DPS] = 5,
92 	[LSM6DSV16X_DT_FS_2000DPS] = 6,
93 	[LSM6DSV16X_DT_FS_4000DPS] = 7,
94 };
95 
96 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
97 /* bit range for Temperature sensor */
98 static const int8_t temp_range = 9;
99 
100 /* transform temperature LSB into micro-Celsius */
101 #define SENSOR_TEMP_UCELSIUS(t_lsb) \
102 	(int64_t) (25000000LL + (((int64_t)(t_lsb) * 1000000LL) / 256LL))
103 
104 #endif
105 
106 /* Calculate scaling factor to transform micro-g/LSB unit into micro-ms2/LSB */
107 #define SENSOR_SCALE_UG_TO_UMS2(ug_lsb)	\
108 	(int32_t)((ug_lsb) * SENSOR_G / 1000000LL)
109 
110 /*
111  * Accelerometer scaling factors table (indexed by full scale)
112  * GAIN_UNIT_XL is expressed in ug/LSB.
113  */
114 static const int32_t accel_scaler[] = {
115 	[LSM6DSV16X_DT_FS_2G] = SENSOR_SCALE_UG_TO_UMS2(GAIN_UNIT_XL),
116 	[LSM6DSV16X_DT_FS_4G] = SENSOR_SCALE_UG_TO_UMS2(2 * GAIN_UNIT_XL),
117 	[LSM6DSV16X_DT_FS_8G] = SENSOR_SCALE_UG_TO_UMS2(4 * GAIN_UNIT_XL),
118 	[LSM6DSV16X_DT_FS_16G] = SENSOR_SCALE_UG_TO_UMS2(8 * GAIN_UNIT_XL),
119 };
120 
121 /* Calculate scaling factor to transform micro-dps/LSB unit into micro-rads/LSB */
122 #define SENSOR_SCALE_UDPS_TO_URADS(udps_lsb) \
123 	(int32_t)(((udps_lsb) * SENSOR_PI / 180LL) / 1000000LL)
124 
125 /*
126  * Accelerometer scaling factors table (indexed by full scale)
127  * GAIN_UNIT_G is expressed in udps/LSB.
128  */
129 static const int32_t gyro_scaler[] = {
130 	[LSM6DSV16X_DT_FS_125DPS] = SENSOR_SCALE_UDPS_TO_URADS(GAIN_UNIT_G),
131 	[LSM6DSV16X_DT_FS_250DPS] = SENSOR_SCALE_UDPS_TO_URADS(2 * GAIN_UNIT_G),
132 	[LSM6DSV16X_DT_FS_500DPS] = SENSOR_SCALE_UDPS_TO_URADS(4 * GAIN_UNIT_G),
133 	[LSM6DSV16X_DT_FS_1000DPS] = SENSOR_SCALE_UDPS_TO_URADS(8 * GAIN_UNIT_G),
134 	[LSM6DSV16X_DT_FS_2000DPS] = SENSOR_SCALE_UDPS_TO_URADS(16 * GAIN_UNIT_G),
135 	[LSM6DSV16X_DT_FS_4000DPS] = SENSOR_SCALE_UDPS_TO_URADS(32 * GAIN_UNIT_G),
136 };
137 
lsm6dsv16x_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)138 static int lsm6dsv16x_decoder_get_frame_count(const uint8_t *buffer,
139 					      struct sensor_chan_spec chan_spec,
140 					      uint16_t *frame_count)
141 {
142 	struct lsm6dsv16x_fifo_data *data = (struct lsm6dsv16x_fifo_data *)buffer;
143 	const struct lsm6dsv16x_decoder_header *header = &data->header;
144 
145 	if (chan_spec.chan_idx != 0) {
146 		return -ENOTSUP;
147 	}
148 
149 	if (!header->is_fifo) {
150 		switch (chan_spec.chan_type) {
151 		case SENSOR_CHAN_ACCEL_X:
152 		case SENSOR_CHAN_ACCEL_Y:
153 		case SENSOR_CHAN_ACCEL_Z:
154 		case SENSOR_CHAN_ACCEL_XYZ:
155 		case SENSOR_CHAN_GYRO_X:
156 		case SENSOR_CHAN_GYRO_Y:
157 		case SENSOR_CHAN_GYRO_Z:
158 		case SENSOR_CHAN_GYRO_XYZ:
159 		case SENSOR_CHAN_DIE_TEMP:
160 			*frame_count = 1;
161 			return 0;
162 		default:
163 			*frame_count = 0;
164 			return -ENOTSUP;
165 		}
166 
167 		return 0;
168 	}
169 
170 #ifdef CONFIG_LSM6DSV16X_STREAM
171 	const struct lsm6dsv16x_fifo_data *edata = (const struct lsm6dsv16x_fifo_data *)buffer;
172 	const uint8_t *buffer_end;
173 	uint8_t fifo_tag;
174 	uint8_t tot_accel_fifo_words = 0, tot_gyro_fifo_words = 0;
175 	uint8_t tot_sflp_gbias = 0, tot_sflp_gravity = 0, tot_sflp_game_rotation = 0;
176 
177 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
178 	uint8_t tot_temp_fifo_words = 0;
179 #endif
180 
181 	buffer += sizeof(struct lsm6dsv16x_fifo_data);
182 	buffer_end = buffer + LSM6DSV16X_FIFO_SIZE(edata->fifo_count);
183 
184 	/* count total FIFO word for each tag */
185 	while (buffer < buffer_end) {
186 		fifo_tag = (buffer[0] >> 3);
187 
188 		switch (fifo_tag) {
189 		case LSM6DSV16X_XL_NC_TAG:
190 			tot_accel_fifo_words++;
191 			break;
192 		case LSM6DSV16X_GY_NC_TAG:
193 			tot_gyro_fifo_words++;
194 			break;
195 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
196 		case LSM6DSV16X_TEMPERATURE_TAG:
197 			tot_temp_fifo_words++;
198 			break;
199 #endif
200 		case LSM6DSV16X_SFLP_GYROSCOPE_BIAS_TAG:
201 			tot_sflp_gbias++;
202 			break;
203 		case LSM6DSV16X_SFLP_GRAVITY_VECTOR_TAG:
204 			tot_sflp_gravity++;
205 			break;
206 		case LSM6DSV16X_SFLP_GAME_ROTATION_VECTOR_TAG:
207 			tot_sflp_game_rotation++;
208 			break;
209 		default:
210 			break;
211 		}
212 
213 		buffer += LSM6DSV16X_FIFO_ITEM_LEN;
214 	}
215 
216 	switch (chan_spec.chan_type) {
217 	case SENSOR_CHAN_ACCEL_X:
218 	case SENSOR_CHAN_ACCEL_Y:
219 	case SENSOR_CHAN_ACCEL_Z:
220 	case SENSOR_CHAN_ACCEL_XYZ:
221 		*frame_count = tot_accel_fifo_words;
222 		break;
223 
224 	case SENSOR_CHAN_GYRO_X:
225 	case SENSOR_CHAN_GYRO_Y:
226 	case SENSOR_CHAN_GYRO_Z:
227 	case SENSOR_CHAN_GYRO_XYZ:
228 		*frame_count = tot_gyro_fifo_words;
229 		break;
230 
231 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
232 	case SENSOR_CHAN_DIE_TEMP:
233 		*frame_count = tot_temp_fifo_words;
234 		break;
235 #endif
236 	case SENSOR_CHAN_GAME_ROTATION_VECTOR:
237 		*frame_count = tot_sflp_game_rotation;
238 		break;
239 	case SENSOR_CHAN_GRAVITY_VECTOR:
240 		*frame_count = tot_sflp_gravity;
241 		break;
242 	case SENSOR_CHAN_GBIAS_XYZ:
243 		*frame_count = tot_sflp_gbias;
244 		break;
245 	default:
246 		*frame_count = 0;
247 		break;
248 	}
249 #endif
250 
251 	return 0;
252 }
253 
254 #ifdef CONFIG_LSM6DSV16X_STREAM
lsm6dsv16x_decode_fifo(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)255 static int lsm6dsv16x_decode_fifo(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
256 				  uint32_t *fit, uint16_t max_count, void *data_out)
257 {
258 	const struct lsm6dsv16x_fifo_data *edata = (const struct lsm6dsv16x_fifo_data *)buffer;
259 	const uint8_t *buffer_end;
260 	const struct lsm6dsv16x_decoder_header *header = &edata->header;
261 	int count = 0;
262 	uint8_t fifo_tag;
263 	uint16_t xl_count = 0, gy_count = 0;
264 	uint16_t tot_chan_fifo_words = 0;
265 
266 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
267 	uint16_t temp_count = 0;
268 #endif
269 	uint16_t game_rot_count = 0, gravity_count = 0, gbias_count = 0;
270 	int ret;
271 
272 	/* count total FIFO word for each tag */
273 	ret = lsm6dsv16x_decoder_get_frame_count(buffer, chan_spec, &tot_chan_fifo_words);
274 	if (ret < 0) {
275 		return 0;
276 	}
277 
278 	buffer += sizeof(struct lsm6dsv16x_fifo_data);
279 	buffer_end = buffer + LSM6DSV16X_FIFO_SIZE(edata->fifo_count);
280 
281 	/*
282 	 * Timestamp in header is set when FIFO threshold is reached, so
283 	 * set time baseline going back in past according to total number
284 	 * of FIFO word for each type.
285 	 */
286 	if (SENSOR_CHANNEL_IS_ACCEL(chan_spec.chan_type)) {
287 		((struct sensor_data_header *)data_out)->base_timestamp_ns =
288 			edata->header.timestamp -
289 			(tot_chan_fifo_words - 1) * accel_period_ns[edata->accel_batch_odr];
290 	} else if (SENSOR_CHANNEL_IS_GYRO(chan_spec.chan_type)) {
291 		((struct sensor_data_header *)data_out)->base_timestamp_ns =
292 			edata->header.timestamp -
293 			(tot_chan_fifo_words - 1) * gyro_period_ns[edata->gyro_batch_odr];
294 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
295 	} else if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
296 		((struct sensor_data_header *)data_out)->base_timestamp_ns =
297 			edata->header.timestamp -
298 			(tot_chan_fifo_words - 1) * temp_period_ns[edata->temp_batch_odr];
299 #endif
300 	} else if (chan_spec.chan_type == SENSOR_CHAN_GRAVITY_VECTOR ||
301 		   chan_spec.chan_type == SENSOR_CHAN_GAME_ROTATION_VECTOR ||
302 		   chan_spec.chan_type == SENSOR_CHAN_GBIAS_XYZ) {
303 		((struct sensor_data_header *)data_out)->base_timestamp_ns =
304 			edata->header.timestamp -
305 			(tot_chan_fifo_words - 1) * sflp_period_ns[edata->sflp_batch_odr];
306 	}
307 
308 	while (count < max_count && buffer < buffer_end) {
309 		const uint8_t *frame_end = buffer;
310 		uint8_t skip_frame;
311 
312 		skip_frame = 0;
313 		frame_end += LSM6DSV16X_FIFO_ITEM_LEN;
314 
315 		fifo_tag = (buffer[0] >> 3);
316 
317 		switch (fifo_tag) {
318 		case LSM6DSV16X_XL_NC_TAG: {
319 			struct sensor_three_axis_data *out = data_out;
320 			int16_t x, y, z;
321 			const int32_t scale = accel_scaler[header->accel_fs];
322 
323 			xl_count++;
324 			if ((uintptr_t)buffer < *fit) {
325 				/* This frame was already decoded, move on to the next frame */
326 				buffer = frame_end;
327 				continue;
328 			}
329 
330 			if (!SENSOR_CHANNEL_IS_ACCEL(chan_spec.chan_type)) {
331 				buffer = frame_end;
332 				continue;
333 			}
334 
335 			out->readings[count].timestamp_delta =
336 				(xl_count - 1) * accel_period_ns[edata->accel_batch_odr];
337 
338 			x = *(int16_t *)&buffer[1];
339 			y = *(int16_t *)&buffer[3];
340 			z = *(int16_t *)&buffer[5];
341 
342 			out->shift = accel_range[header->accel_fs];
343 
344 			out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift);
345 			out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift);
346 			out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift);
347 			break;
348 		}
349 		case LSM6DSV16X_GY_NC_TAG: {
350 			struct sensor_three_axis_data *out = data_out;
351 			int16_t x, y, z;
352 			const int32_t scale = gyro_scaler[header->gyro_fs];
353 
354 			gy_count++;
355 			if ((uintptr_t)buffer < *fit) {
356 				/* This frame was already decoded, move on to the next frame */
357 				buffer = frame_end;
358 				continue;
359 			}
360 
361 			if (!SENSOR_CHANNEL_IS_GYRO(chan_spec.chan_type)) {
362 				buffer = frame_end;
363 				continue;
364 			}
365 
366 			out->readings[count].timestamp_delta =
367 				(gy_count - 1) * gyro_period_ns[edata->gyro_batch_odr];
368 
369 			x = *(int16_t *)&buffer[1];
370 			y = *(int16_t *)&buffer[3];
371 			z = *(int16_t *)&buffer[5];
372 
373 			out->shift = gyro_range[header->gyro_fs];
374 
375 			out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift);
376 			out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift);
377 			out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift);
378 			break;
379 		}
380 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
381 		case LSM6DSV16X_TEMPERATURE_TAG: {
382 			struct sensor_q31_data *out = data_out;
383 			int16_t t;
384 			int64_t t_uC;
385 
386 			temp_count++;
387 			if ((uintptr_t)buffer < *fit) {
388 				/* This frame was already decoded, move on to the next frame */
389 				buffer = frame_end;
390 				continue;
391 			}
392 
393 			if (chan_spec.chan_type != SENSOR_CHAN_DIE_TEMP) {
394 				buffer = frame_end;
395 				continue;
396 			}
397 
398 			out->readings[count].timestamp_delta =
399 				(temp_count - 1) * temp_period_ns[edata->temp_batch_odr];
400 
401 			t = *(int16_t *)&buffer[1];
402 			t_uC = SENSOR_TEMP_UCELSIUS(t);
403 
404 			out->shift = temp_range;
405 
406 			out->readings[count].temperature = Q31_SHIFT_MICROVAL(t_uC, out->shift);
407 			break;
408 		}
409 #endif
410 		case LSM6DSV16X_SFLP_GAME_ROTATION_VECTOR_TAG: {
411 			struct sensor_game_rotation_vector_data *out = data_out;
412 			union { float32_t f; uint32_t i; } x, y, z;
413 			float32_t w, sumsq;
414 
415 			game_rot_count++;
416 			if ((uintptr_t)buffer < *fit) {
417 				/* This frame was already decoded, move on to the next frame */
418 				buffer = frame_end;
419 				continue;
420 			}
421 
422 			if (chan_spec.chan_type != SENSOR_CHAN_GAME_ROTATION_VECTOR) {
423 				buffer = frame_end;
424 				continue;
425 			}
426 
427 			out->readings[count].timestamp_delta =
428 				(game_rot_count - 1) * sflp_period_ns[edata->sflp_batch_odr];
429 
430 			x.i = lsm6dsv16x_from_f16_to_f32(buffer[1] | (buffer[2] << 8));
431 			y.i = lsm6dsv16x_from_f16_to_f32(buffer[3] | (buffer[4] << 8));
432 			z.i = lsm6dsv16x_from_f16_to_f32(buffer[5] | (buffer[6] << 8));
433 
434 			sumsq = powf(x.f, 2) + powf(y.f, 2) + powf(z.f, 2);
435 
436 			/*
437 			 * Theoretically sumsq should never be greater than 1, but due to
438 			 * lack of precision it might happen. So, add a software correction
439 			 * which consists in normalizing the (x, y, z) vector.
440 			 */
441 			if (sumsq > 1.0f) {
442 				float n = sqrtf(sumsq);
443 
444 				x.f /= n;
445 				y.f /= n;
446 				z.f /= n;
447 				sumsq = 1.0f;
448 			}
449 
450 			/* unity vector quaternions */
451 			w = sqrtf(1.0f - sumsq);
452 
453 			/*
454 			 * Quaternions are numbers between -1 and 1. So let's select the signed
455 			 * Q0.31 format (m = 0, n (fractional bits) == 31)
456 			 */
457 			out->shift = 0;
458 
459 			out->readings[count].x = Q31_SHIFT_VAL(x.f, out->shift);
460 			out->readings[count].y = Q31_SHIFT_VAL(y.f, out->shift);
461 			out->readings[count].z = Q31_SHIFT_VAL(z.f, out->shift);
462 			out->readings[count].w = Q31_SHIFT_VAL(w, out->shift);
463 
464 			break;
465 		}
466 
467 		case LSM6DSV16X_SFLP_GYROSCOPE_BIAS_TAG: {
468 			struct sensor_three_axis_data *out = data_out;
469 			int16_t x, y, z;
470 			const int32_t scale = gyro_scaler[LSM6DSV16X_DT_FS_125DPS];
471 
472 			gbias_count++;
473 			if ((uintptr_t)buffer < *fit) {
474 				/* This frame was already decoded, move on to the next frame */
475 				buffer = frame_end;
476 				continue;
477 			}
478 
479 			if (chan_spec.chan_type != SENSOR_CHAN_GBIAS_XYZ) {
480 				buffer = frame_end;
481 				continue;
482 			}
483 
484 			out->readings[count].timestamp_delta =
485 				(gbias_count - 1) * sflp_period_ns[edata->sflp_batch_odr];
486 
487 			x = buffer[1] | (buffer[2] << 8);
488 			y = buffer[3] | (buffer[4] << 8);
489 			z = buffer[5] | (buffer[6] << 8);
490 
491 			out->shift = gyro_range[LSM6DSV16X_DT_FS_125DPS];
492 
493 			out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift);
494 			out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift);
495 			out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift);
496 			break;
497 		}
498 
499 		case LSM6DSV16X_SFLP_GRAVITY_VECTOR_TAG: {
500 			struct sensor_three_axis_data *out = data_out;
501 			float32_t x, y, z;
502 
503 			gravity_count++;
504 			if ((uintptr_t)buffer < *fit) {
505 				/* This frame was already decoded, move on to the next frame */
506 				buffer = frame_end;
507 				continue;
508 			}
509 
510 			if (chan_spec.chan_type != SENSOR_CHAN_GRAVITY_VECTOR) {
511 				buffer = frame_end;
512 				continue;
513 			}
514 
515 			out->readings[count].timestamp_delta =
516 				(gravity_count - 1) * sflp_period_ns[edata->sflp_batch_odr];
517 
518 			x = lsm6dsv16x_from_sflp_to_mg(buffer[1] | (buffer[2] << 8));
519 			y = lsm6dsv16x_from_sflp_to_mg(buffer[3] | (buffer[4] << 8));
520 			z = lsm6dsv16x_from_sflp_to_mg(buffer[5] | (buffer[6] << 8));
521 
522 			out->shift = 12;
523 
524 			out->readings[count].x = Q31_SHIFT_VAL(x, out->shift);
525 			out->readings[count].y = Q31_SHIFT_VAL(y, out->shift);
526 			out->readings[count].z = Q31_SHIFT_VAL(z, out->shift);
527 			break;
528 		}
529 
530 		default:
531 			/* skip unhandled FIFO tag */
532 			buffer = frame_end;
533 			LOG_DBG("unknown FIFO tag %02x", fifo_tag);
534 			continue;
535 		}
536 
537 		buffer = frame_end;
538 		*fit = (uintptr_t)frame_end;
539 		count++;
540 	}
541 
542 	return count;
543 }
544 #endif /* CONFIG_LSM6DSV16X_STREAM */
545 
lsm6dsv16x_decode_sample(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)546 static int lsm6dsv16x_decode_sample(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
547 				    uint32_t *fit, uint16_t max_count, void *data_out)
548 {
549 	const struct lsm6dsv16x_rtio_data *edata = (const struct lsm6dsv16x_rtio_data *)buffer;
550 	const struct lsm6dsv16x_decoder_header *header = &edata->header;
551 
552 	if (*fit != 0) {
553 		return 0;
554 	}
555 	if (max_count == 0 || chan_spec.chan_idx != 0) {
556 		return -EINVAL;
557 	}
558 
559 	switch (chan_spec.chan_type) {
560 	case SENSOR_CHAN_ACCEL_X:
561 	case SENSOR_CHAN_ACCEL_Y:
562 	case SENSOR_CHAN_ACCEL_Z:
563 	case SENSOR_CHAN_ACCEL_XYZ: {
564 		const int32_t scale = accel_scaler[header->accel_fs];
565 
566 		if (edata->has_accel == 0) {
567 			return -ENODATA;
568 		}
569 
570 		struct sensor_three_axis_data *out = data_out;
571 
572 		out->header.base_timestamp_ns = edata->header.timestamp;
573 		out->header.reading_count = 1;
574 
575 		out->shift = accel_range[header->accel_fs];
576 
577 		out->readings[0].x = Q31_SHIFT_MICROVAL(scale * edata->acc[0], out->shift);
578 		out->readings[0].y = Q31_SHIFT_MICROVAL(scale * edata->acc[1], out->shift);
579 		out->readings[0].z = Q31_SHIFT_MICROVAL(scale * edata->acc[2], out->shift);
580 		*fit = 1;
581 		return 1;
582 	}
583 	case SENSOR_CHAN_GYRO_X:
584 	case SENSOR_CHAN_GYRO_Y:
585 	case SENSOR_CHAN_GYRO_Z:
586 	case SENSOR_CHAN_GYRO_XYZ: {
587 		const int32_t scale = gyro_scaler[header->gyro_fs];
588 
589 		if (edata->has_gyro == 0) {
590 			return -ENODATA;
591 		}
592 
593 		struct sensor_three_axis_data *out = data_out;
594 
595 		out->header.base_timestamp_ns = edata->header.timestamp;
596 		out->header.reading_count = 1;
597 
598 		out->shift = gyro_range[header->gyro_fs];
599 
600 		out->readings[0].x = Q31_SHIFT_MICROVAL(scale * edata->gyro[0], out->shift);
601 		out->readings[0].y = Q31_SHIFT_MICROVAL(scale * edata->gyro[1], out->shift);
602 		out->readings[0].z = Q31_SHIFT_MICROVAL(scale * edata->gyro[2], out->shift);
603 		*fit = 1;
604 		return 1;
605 	}
606 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
607 	case SENSOR_CHAN_DIE_TEMP: {
608 		int64_t t_uC;
609 
610 		if (edata->has_temp == 0) {
611 			return -ENODATA;
612 		}
613 
614 		struct sensor_q31_data *out = data_out;
615 
616 		out->header.base_timestamp_ns = edata->header.timestamp;
617 		out->header.reading_count = 1;
618 
619 		out->shift = temp_range;
620 
621 		/* transform temperature LSB into micro-Celsius */
622 		t_uC = SENSOR_TEMP_UCELSIUS(edata->temp);
623 
624 		out->readings[0].temperature = Q31_SHIFT_MICROVAL(t_uC, out->shift);
625 		*fit = 1;
626 		return 1;
627 	}
628 #endif
629 	default:
630 		return -EINVAL;
631 	}
632 }
633 
lsm6dsv16x_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)634 static int lsm6dsv16x_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
635 				     uint32_t *fit, uint16_t max_count, void *data_out)
636 {
637 #ifdef CONFIG_LSM6DSV16X_STREAM
638 	const struct lsm6dsv16x_decoder_header *header =
639 		(const struct lsm6dsv16x_decoder_header *)buffer;
640 
641 	if (header->is_fifo) {
642 		return lsm6dsv16x_decode_fifo(buffer, chan_spec, fit, max_count, data_out);
643 	}
644 #endif
645 
646 	return lsm6dsv16x_decode_sample(buffer, chan_spec, fit, max_count, data_out);
647 }
648 
lsm6dsv16x_decoder_get_size_info(struct sensor_chan_spec chan_spec,size_t * base_size,size_t * frame_size)649 static int lsm6dsv16x_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size,
650 					    size_t *frame_size)
651 {
652 	switch (chan_spec.chan_type) {
653 	case SENSOR_CHAN_ACCEL_X:
654 	case SENSOR_CHAN_ACCEL_Y:
655 	case SENSOR_CHAN_ACCEL_Z:
656 	case SENSOR_CHAN_ACCEL_XYZ:
657 	case SENSOR_CHAN_GYRO_X:
658 	case SENSOR_CHAN_GYRO_Y:
659 	case SENSOR_CHAN_GYRO_Z:
660 	case SENSOR_CHAN_GYRO_XYZ:
661 		*base_size = sizeof(struct sensor_three_axis_data);
662 		*frame_size = sizeof(struct sensor_three_axis_sample_data);
663 		return 0;
664 	case SENSOR_CHAN_DIE_TEMP:
665 		*base_size = sizeof(struct sensor_q31_data);
666 		*frame_size = sizeof(struct sensor_q31_sample_data);
667 		return 0;
668 	default:
669 		return -ENOTSUP;
670 	}
671 }
672 
lsm6dsv16x_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)673 static bool lsm6dsv16x_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
674 {
675 	return false;
676 }
677 
678 SENSOR_DECODER_API_DT_DEFINE() = {
679 	.get_frame_count = lsm6dsv16x_decoder_get_frame_count,
680 	.get_size_info = lsm6dsv16x_decoder_get_size_info,
681 	.decode = lsm6dsv16x_decoder_decode,
682 	.has_trigger = lsm6dsv16x_decoder_has_trigger,
683 };
684 
lsm6dsv16x_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)685 int lsm6dsv16x_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
686 {
687 	ARG_UNUSED(dev);
688 	*decoder = &SENSOR_DECODER_NAME();
689 
690 	return 0;
691 }
692