1 /* ST Microelectronics ISM330DHCX 6-axis IMU sensor driver
2  *
3  * Copyright (c) 2020 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/ism330dhcx.pdf
9  */
10 
11 #define DT_DRV_COMPAT st_ism330dhcx
12 
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <string.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/sys/util_macro.h>
20 #include <zephyr/logging/log.h>
21 
22 #include "ism330dhcx.h"
23 
24 LOG_MODULE_REGISTER(ISM330DHCX, CONFIG_SENSOR_LOG_LEVEL);
25 
26 static const uint16_t ism330dhcx_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833,
27 					1660, 3330, 6660};
28 
ism330dhcx_freq_to_odr_val(uint16_t freq)29 static int ism330dhcx_freq_to_odr_val(uint16_t freq)
30 {
31 	size_t i;
32 
33 	for (i = 0; i < ARRAY_SIZE(ism330dhcx_odr_map); i++) {
34 		if (freq <= ism330dhcx_odr_map[i]) {
35 			return i;
36 		}
37 	}
38 
39 	return -EINVAL;
40 }
41 
ism330dhcx_odr_to_freq_val(uint16_t odr)42 static int ism330dhcx_odr_to_freq_val(uint16_t odr)
43 {
44 	/* for valid index, return value from map */
45 	if (odr < ARRAY_SIZE(ism330dhcx_odr_map)) {
46 		return ism330dhcx_odr_map[odr];
47 	}
48 
49 	/* invalid index, return last entry */
50 	return ism330dhcx_odr_map[ARRAY_SIZE(ism330dhcx_odr_map) - 1];
51 }
52 
53 static const uint16_t ism330dhcx_accel_fs_map[] = {2, 16, 4, 8};
54 static const uint16_t ism330dhcx_accel_fs_sens[] = {1, 8, 2, 4};
55 
ism330dhcx_accel_range_to_fs_val(int32_t range)56 static int ism330dhcx_accel_range_to_fs_val(int32_t range)
57 {
58 	size_t i;
59 
60 	for (i = 0; i < ARRAY_SIZE(ism330dhcx_accel_fs_map); i++) {
61 		if (range == ism330dhcx_accel_fs_map[i]) {
62 			return i;
63 		}
64 	}
65 
66 	return -EINVAL;
67 }
68 
69 /*
70  * Following arrays are initialized in order to mimic
71  * the ism330dhcx_fs_g_t enum:
72  *
73  * typedef enum
74  * {
75  *   ISM330DHCX_125dps = 2,
76  *   ISM330DHCX_250dps = 0,
77  *   ISM330DHCX_500dps = 4,
78  *   ISM330DHCX_1000dps = 8,
79  *   ISM330DHCX_2000dps = 12,
80  *   ISM330DHCX_4000dps = 1,
81  * } ism330dhcx_fs_g_t;
82  */
83 static const uint16_t ism330dhcx_gyro_fs_map[] = {
84 				250, 4000, 125, 0, 500,
85 				0, 0, 0, 1000,
86 				0, 0, 0, 2000
87 				};
88 static const uint16_t ism330dhcx_gyro_fs_sens[] = {
89 				2, 32, 1, 0, 4,
90 				0, 0, 0, 8,
91 				0, 0, 0, 16
92 				};
93 
ism330dhcx_gyro_range_to_fs_val(int32_t range)94 static int ism330dhcx_gyro_range_to_fs_val(int32_t range)
95 {
96 	size_t i;
97 
98 	for (i = 0; i < ARRAY_SIZE(ism330dhcx_gyro_fs_map); i++) {
99 		if (range == ism330dhcx_gyro_fs_map[i]) {
100 			return i;
101 		}
102 	}
103 
104 	return -EINVAL;
105 }
106 
ism330dhcx_reboot(const struct device * dev)107 static inline int ism330dhcx_reboot(const struct device *dev)
108 {
109 	struct ism330dhcx_data *data = dev->data;
110 
111 	if (ism330dhcx_boot_set(data->ctx, 1) < 0) {
112 		return -EIO;
113 	}
114 
115 	/* Wait sensor turn-on time as per datasheet */
116 	k_busy_wait(35 * USEC_PER_MSEC);
117 
118 	return 0;
119 }
120 
ism330dhcx_accel_set_fs_raw(const struct device * dev,uint8_t fs)121 static int ism330dhcx_accel_set_fs_raw(const struct device *dev, uint8_t fs)
122 {
123 	struct ism330dhcx_data *data = dev->data;
124 
125 	if (ism330dhcx_xl_full_scale_set(data->ctx, fs) < 0) {
126 		return -EIO;
127 	}
128 
129 	data->accel_fs = fs;
130 
131 	return 0;
132 }
133 
ism330dhcx_accel_set_odr_raw(const struct device * dev,uint8_t odr)134 static int ism330dhcx_accel_set_odr_raw(const struct device *dev, uint8_t odr)
135 {
136 	struct ism330dhcx_data *data = dev->data;
137 
138 	if (ism330dhcx_xl_data_rate_set(data->ctx, odr) < 0) {
139 		return -EIO;
140 	}
141 
142 	data->accel_freq = ism330dhcx_odr_to_freq_val(odr);
143 
144 	return 0;
145 }
146 
ism330dhcx_gyro_set_fs_raw(const struct device * dev,uint8_t fs)147 static int ism330dhcx_gyro_set_fs_raw(const struct device *dev, uint8_t fs)
148 {
149 	struct ism330dhcx_data *data = dev->data;
150 
151 	if (ism330dhcx_gy_full_scale_set(data->ctx, fs) < 0) {
152 		return -EIO;
153 	}
154 
155 	return 0;
156 }
157 
ism330dhcx_gyro_set_odr_raw(const struct device * dev,uint8_t odr)158 static int ism330dhcx_gyro_set_odr_raw(const struct device *dev, uint8_t odr)
159 {
160 	struct ism330dhcx_data *data = dev->data;
161 
162 	if (ism330dhcx_gy_data_rate_set(data->ctx, odr) < 0) {
163 		return -EIO;
164 	}
165 
166 	return 0;
167 }
168 
ism330dhcx_accel_odr_set(const struct device * dev,uint16_t freq)169 static int ism330dhcx_accel_odr_set(const struct device *dev, uint16_t freq)
170 {
171 	int odr;
172 
173 	odr = ism330dhcx_freq_to_odr_val(freq);
174 	if (odr < 0) {
175 		return odr;
176 	}
177 
178 	if (ism330dhcx_accel_set_odr_raw(dev, odr) < 0) {
179 		LOG_DBG("failed to set accelerometer sampling rate");
180 		return -EIO;
181 	}
182 
183 	return 0;
184 }
185 
ism330dhcx_accel_range_set(const struct device * dev,int32_t range)186 static int ism330dhcx_accel_range_set(const struct device *dev, int32_t range)
187 {
188 	int fs;
189 	struct ism330dhcx_data *data = dev->data;
190 
191 	fs = ism330dhcx_accel_range_to_fs_val(range);
192 	if (fs < 0) {
193 		return fs;
194 	}
195 
196 	if (ism330dhcx_accel_set_fs_raw(dev, fs) < 0) {
197 		LOG_DBG("failed to set accelerometer full-scale");
198 		return -EIO;
199 	}
200 
201 	data->acc_gain = (ism330dhcx_accel_fs_sens[fs] * GAIN_UNIT_XL);
202 	return 0;
203 }
204 
ism330dhcx_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)205 static int ism330dhcx_accel_config(const struct device *dev,
206 				   enum sensor_channel chan,
207 				   enum sensor_attribute attr,
208 				   const struct sensor_value *val)
209 {
210 	switch (attr) {
211 	case SENSOR_ATTR_FULL_SCALE:
212 		return ism330dhcx_accel_range_set(dev, sensor_ms2_to_g(val));
213 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
214 		return ism330dhcx_accel_odr_set(dev, val->val1);
215 	default:
216 		LOG_DBG("Accel attribute not supported.");
217 		return -ENOTSUP;
218 	}
219 
220 	return 0;
221 }
222 
ism330dhcx_gyro_odr_set(const struct device * dev,uint16_t freq)223 static int ism330dhcx_gyro_odr_set(const struct device *dev, uint16_t freq)
224 {
225 	int odr;
226 
227 	odr = ism330dhcx_freq_to_odr_val(freq);
228 	if (odr < 0) {
229 		return odr;
230 	}
231 
232 	if (ism330dhcx_gyro_set_odr_raw(dev, odr) < 0) {
233 		LOG_DBG("failed to set gyroscope sampling rate");
234 		return -EIO;
235 	}
236 
237 	return 0;
238 }
239 
ism330dhcx_gyro_range_set(const struct device * dev,int32_t range)240 static int ism330dhcx_gyro_range_set(const struct device *dev, int32_t range)
241 {
242 	int fs;
243 	struct ism330dhcx_data *data = dev->data;
244 
245 	fs = ism330dhcx_gyro_range_to_fs_val(range);
246 	if (fs < 0) {
247 		return fs;
248 	}
249 
250 	if (ism330dhcx_gyro_set_fs_raw(dev, fs) < 0) {
251 		LOG_DBG("failed to set gyroscope full-scale");
252 		return -EIO;
253 	}
254 
255 	data->gyro_gain = (ism330dhcx_gyro_fs_sens[fs] * GAIN_UNIT_G);
256 	return 0;
257 }
258 
ism330dhcx_gyro_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)259 static int ism330dhcx_gyro_config(const struct device *dev,
260 				  enum sensor_channel chan,
261 				  enum sensor_attribute attr,
262 				  const struct sensor_value *val)
263 {
264 	switch (attr) {
265 	case SENSOR_ATTR_FULL_SCALE:
266 		return ism330dhcx_gyro_range_set(dev, sensor_rad_to_degrees(val));
267 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
268 		return ism330dhcx_gyro_odr_set(dev, val->val1);
269 	default:
270 		LOG_DBG("Gyro attribute not supported.");
271 		return -ENOTSUP;
272 	}
273 
274 	return 0;
275 }
276 
ism330dhcx_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)277 static int ism330dhcx_attr_set(const struct device *dev,
278 			       enum sensor_channel chan,
279 			       enum sensor_attribute attr,
280 			       const struct sensor_value *val)
281 {
282 	switch (chan) {
283 	case SENSOR_CHAN_ACCEL_XYZ:
284 		return ism330dhcx_accel_config(dev, chan, attr, val);
285 	case SENSOR_CHAN_GYRO_XYZ:
286 		return ism330dhcx_gyro_config(dev, chan, attr, val);
287 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
288 	case SENSOR_CHAN_MAGN_XYZ:
289 	case SENSOR_CHAN_PRESS:
290 	case SENSOR_CHAN_HUMIDITY:
291 		return ism330dhcx_shub_config(dev, chan, attr, val);
292 #endif /* CONFIG_ISM330DHCX_SENSORHUB */
293 	default:
294 		LOG_WRN("attr_set() not supported on this channel.");
295 		return -ENOTSUP;
296 	}
297 
298 	return 0;
299 }
300 
ism330dhcx_sample_fetch_accel(const struct device * dev)301 static int ism330dhcx_sample_fetch_accel(const struct device *dev)
302 {
303 	struct ism330dhcx_data *data = dev->data;
304 	int16_t buf[3];
305 
306 	if (ism330dhcx_acceleration_raw_get(data->ctx, buf) < 0) {
307 		LOG_DBG("Failed to read sample");
308 		return -EIO;
309 	}
310 
311 	data->acc[0] = buf[0];
312 	data->acc[1] = buf[1];
313 	data->acc[2] = buf[2];
314 
315 	return 0;
316 }
317 
ism330dhcx_sample_fetch_gyro(const struct device * dev)318 static int ism330dhcx_sample_fetch_gyro(const struct device *dev)
319 {
320 	struct ism330dhcx_data *data = dev->data;
321 	int16_t buf[3];
322 
323 	if (ism330dhcx_angular_rate_raw_get(data->ctx, buf) < 0) {
324 		LOG_DBG("Failed to read sample");
325 		return -EIO;
326 	}
327 
328 	data->gyro[0] = buf[0];
329 	data->gyro[1] = buf[1];
330 	data->gyro[2] = buf[2];
331 
332 	return 0;
333 }
334 
335 #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP)
ism330dhcx_sample_fetch_temp(const struct device * dev)336 static int ism330dhcx_sample_fetch_temp(const struct device *dev)
337 {
338 	struct ism330dhcx_data *data = dev->data;
339 	int16_t buf;
340 
341 	if (ism330dhcx_temperature_raw_get(data->ctx, &buf) < 0) {
342 		LOG_DBG("Failed to read sample");
343 		return -EIO;
344 	}
345 
346 	data->temp_sample = buf;
347 
348 	return 0;
349 }
350 #endif
351 
352 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
ism330dhcx_sample_fetch_shub(const struct device * dev)353 static int ism330dhcx_sample_fetch_shub(const struct device *dev)
354 {
355 	if (ism330dhcx_shub_fetch_external_devs(dev) < 0) {
356 		LOG_DBG("failed to read ext shub devices");
357 		return -EIO;
358 	}
359 
360 	return 0;
361 }
362 #endif /* CONFIG_ISM330DHCX_SENSORHUB */
363 
ism330dhcx_sample_fetch(const struct device * dev,enum sensor_channel chan)364 static int ism330dhcx_sample_fetch(const struct device *dev,
365 				   enum sensor_channel chan)
366 {
367 	switch (chan) {
368 	case SENSOR_CHAN_ACCEL_XYZ:
369 		ism330dhcx_sample_fetch_accel(dev);
370 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
371 		ism330dhcx_sample_fetch_shub(dev);
372 #endif
373 		break;
374 	case SENSOR_CHAN_GYRO_XYZ:
375 		ism330dhcx_sample_fetch_gyro(dev);
376 		break;
377 #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP)
378 	case SENSOR_CHAN_DIE_TEMP:
379 		ism330dhcx_sample_fetch_temp(dev);
380 		break;
381 #endif
382 	case SENSOR_CHAN_ALL:
383 		ism330dhcx_sample_fetch_accel(dev);
384 		ism330dhcx_sample_fetch_gyro(dev);
385 #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP)
386 		ism330dhcx_sample_fetch_temp(dev);
387 #endif
388 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
389 		ism330dhcx_sample_fetch_shub(dev);
390 #endif
391 		break;
392 	default:
393 		return -ENOTSUP;
394 	}
395 
396 	return 0;
397 }
398 
ism330dhcx_accel_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)399 static inline void ism330dhcx_accel_convert(struct sensor_value *val, int raw_val,
400 					    uint32_t sensitivity)
401 {
402 	int64_t dval;
403 
404 	/* Sensitivity is exposed in ug/LSB */
405 	/* Convert to m/s^2 */
406 	dval = (int64_t)(raw_val) * sensitivity;
407 	sensor_ug_to_ms2(dval, val);
408 
409 }
410 
ism330dhcx_accel_get_channel(const struct device * dev,enum sensor_channel chan,struct sensor_value * val,uint32_t sensitivity)411 static inline int ism330dhcx_accel_get_channel(const struct device *dev, enum sensor_channel chan,
412 					       struct sensor_value *val, uint32_t sensitivity)
413 {
414 	struct ism330dhcx_data *data = dev->data;
415 	uint8_t i;
416 
417 	switch (chan) {
418 	case SENSOR_CHAN_ACCEL_X:
419 		ism330dhcx_accel_convert(val, data->acc[0], sensitivity);
420 		break;
421 	case SENSOR_CHAN_ACCEL_Y:
422 		ism330dhcx_accel_convert(val, data->acc[1], sensitivity);
423 		break;
424 	case SENSOR_CHAN_ACCEL_Z:
425 		ism330dhcx_accel_convert(val, data->acc[2], sensitivity);
426 		break;
427 	case SENSOR_CHAN_ACCEL_XYZ:
428 		for (i = 0; i < 3; i++) {
429 			ism330dhcx_accel_convert(val++, data->acc[i], sensitivity);
430 		}
431 		break;
432 	default:
433 		return -ENOTSUP;
434 	}
435 
436 	return 0;
437 }
438 
ism330dhcx_accel_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)439 static int ism330dhcx_accel_channel_get(const struct device *dev, enum sensor_channel chan,
440 					struct sensor_value *val)
441 {
442 	struct ism330dhcx_data *data = dev->data;
443 
444 	return ism330dhcx_accel_get_channel(dev, chan, val, data->acc_gain);
445 }
446 
ism330dhcx_gyro_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)447 static inline void ism330dhcx_gyro_convert(struct sensor_value *val, int raw_val,
448 					   uint32_t sensitivity)
449 {
450 	int64_t dval;
451 
452 	/* Sensitivity is exposed in udps/LSB */
453 	/* So, calculate value in 10 udps unit and then to rad/s */
454 	dval = (int64_t)(raw_val) * sensitivity / 10;
455 	sensor_10udegrees_to_rad(dval, val);
456 }
457 
ism330dhcx_gyro_get_channel(const struct device * dev,enum sensor_channel chan,struct sensor_value * val,uint32_t sensitivity)458 static inline int ism330dhcx_gyro_get_channel(const struct device *dev, enum sensor_channel chan,
459 					      struct sensor_value *val, uint32_t sensitivity)
460 {
461 	struct ism330dhcx_data *data = dev->data;
462 	uint8_t i;
463 
464 	switch (chan) {
465 	case SENSOR_CHAN_GYRO_X:
466 		ism330dhcx_gyro_convert(val, data->gyro[0], sensitivity);
467 		break;
468 	case SENSOR_CHAN_GYRO_Y:
469 		ism330dhcx_gyro_convert(val, data->gyro[1], sensitivity);
470 		break;
471 	case SENSOR_CHAN_GYRO_Z:
472 		ism330dhcx_gyro_convert(val, data->gyro[2], sensitivity);
473 		break;
474 	case SENSOR_CHAN_GYRO_XYZ:
475 		for (i = 0; i < 3; i++) {
476 			ism330dhcx_gyro_convert(val++, data->gyro[i], sensitivity);
477 		}
478 		break;
479 	default:
480 		return -ENOTSUP;
481 	}
482 
483 	return 0;
484 }
485 
ism330dhcx_gyro_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)486 static int ism330dhcx_gyro_channel_get(const struct device *dev, enum sensor_channel chan,
487 				       struct sensor_value *val)
488 {
489 	struct ism330dhcx_data *data = dev->data;
490 
491 	return ism330dhcx_gyro_get_channel(dev, chan, val, data->gyro_gain);
492 }
493 
494 #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP)
ism330dhcx_gyro_channel_get_temp(const struct device * dev,struct sensor_value * val)495 static void ism330dhcx_gyro_channel_get_temp(const struct device *dev,
496 					     struct sensor_value *val)
497 {
498 	struct ism330dhcx_data *data = dev->data;
499 
500 	/* val = temp_sample / 256 + 25 */
501 	val->val1 = data->temp_sample / 256 + 25;
502 	val->val2 = (data->temp_sample % 256) * (1000000 / 256);
503 }
504 #endif
505 
506 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
ism330dhcx_magn_convert(struct sensor_value * val,int raw_val,uint16_t sensitivity)507 static inline void ism330dhcx_magn_convert(struct sensor_value *val, int raw_val,
508 					   uint16_t sensitivity)
509 {
510 	double dval;
511 
512 	/* Sensitivity is exposed in ugauss/LSB */
513 	dval = (double)(raw_val * sensitivity);
514 	val->val1 = (int32_t)dval / 1000000;
515 	val->val2 = (int32_t)dval % 1000000;
516 }
517 
ism330dhcx_magn_get_channel(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)518 static inline int ism330dhcx_magn_get_channel(const struct device *dev, enum sensor_channel chan,
519 					      struct sensor_value *val)
520 {
521 	struct ism330dhcx_data *data = dev->data;
522 	int16_t sample[3];
523 	int idx;
524 
525 	idx = ism330dhcx_shub_get_idx(SENSOR_CHAN_MAGN_XYZ);
526 	if (idx < 0) {
527 		LOG_DBG("external magn not supported");
528 		return -ENOTSUP;
529 	}
530 
531 
532 	sample[0] = (int16_t)(data->ext_data[idx][0] |
533 			    (data->ext_data[idx][1] << 8));
534 	sample[1] = (int16_t)(data->ext_data[idx][2] |
535 			    (data->ext_data[idx][3] << 8));
536 	sample[2] = (int16_t)(data->ext_data[idx][4] |
537 			    (data->ext_data[idx][5] << 8));
538 
539 	switch (chan) {
540 	case SENSOR_CHAN_MAGN_X:
541 		ism330dhcx_magn_convert(val, sample[0], data->magn_gain);
542 		break;
543 	case SENSOR_CHAN_MAGN_Y:
544 		ism330dhcx_magn_convert(val, sample[1], data->magn_gain);
545 		break;
546 	case SENSOR_CHAN_MAGN_Z:
547 		ism330dhcx_magn_convert(val, sample[2], data->magn_gain);
548 		break;
549 	case SENSOR_CHAN_MAGN_XYZ:
550 		ism330dhcx_magn_convert(val, sample[0], data->magn_gain);
551 		ism330dhcx_magn_convert(val + 1, sample[1], data->magn_gain);
552 		ism330dhcx_magn_convert(val + 2, sample[2], data->magn_gain);
553 		break;
554 	default:
555 		return -ENOTSUP;
556 	}
557 
558 	return 0;
559 }
560 
ism330dhcx_hum_convert(const struct device * dev,struct sensor_value * val)561 static inline void ism330dhcx_hum_convert(const struct device *dev, struct sensor_value *val)
562 {
563 	struct ism330dhcx_data *data = dev->data;
564 	float rh;
565 	int16_t raw_val;
566 	struct hts221_data *ht = &data->hts221;
567 	int idx;
568 
569 	idx = ism330dhcx_shub_get_idx(SENSOR_CHAN_HUMIDITY);
570 	if (idx < 0) {
571 		LOG_DBG("external press/temp not supported");
572 		return;
573 	}
574 
575 	raw_val = ((int16_t)(data->ext_data[idx][0] |
576 			   (data->ext_data[idx][1] << 8)));
577 
578 	/* find relative humidty by linear interpolation */
579 	rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1;
580 	rh /= (ht->x1 - ht->x0);
581 
582 	/* convert humidity to integer and fractional part */
583 	val->val1 = rh;
584 	val->val2 = rh * 1000000;
585 }
586 
ism330dhcx_press_convert(const struct device * dev,struct sensor_value * val)587 static inline void ism330dhcx_press_convert(const struct device *dev, struct sensor_value *val)
588 {
589 	struct ism330dhcx_data *data = dev->data;
590 	int32_t raw_val;
591 	int idx;
592 
593 	idx = ism330dhcx_shub_get_idx(SENSOR_CHAN_PRESS);
594 	if (idx < 0) {
595 		LOG_DBG("external press/temp not supported");
596 		return;
597 	}
598 
599 	raw_val = (int32_t)(data->ext_data[idx][0] |
600 			  (data->ext_data[idx][1] << 8) |
601 			  (data->ext_data[idx][2] << 16));
602 
603 	/* Pressure sensitivity is 4096 LSB/hPa */
604 	/* Convert raw_val to val in kPa */
605 	val->val1 = (raw_val >> 12) / 10;
606 	val->val2 = (raw_val >> 12) % 10 * 100000 +
607 		(((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
608 }
609 
ism330dhcx_temp_convert(const struct device * dev,struct sensor_value * val)610 static inline void ism330dhcx_temp_convert(const struct device *dev, struct sensor_value *val)
611 {
612 	struct ism330dhcx_data *data = dev->data;
613 	int16_t raw_val;
614 	int idx;
615 
616 	idx = ism330dhcx_shub_get_idx(SENSOR_CHAN_PRESS);
617 	if (idx < 0) {
618 		LOG_DBG("external press/temp not supported");
619 		return;
620 	}
621 
622 	raw_val = (int16_t)(data->ext_data[idx][3] |
623 			  (data->ext_data[idx][4] << 8));
624 
625 	/* Temperature sensitivity is 100 LSB/deg C */
626 	val->val1 = raw_val / 100;
627 	val->val2 = (int32_t)raw_val % 100 * (10000);
628 }
629 #endif
630 
ism330dhcx_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)631 static int ism330dhcx_channel_get(const struct device *dev,
632 				  enum sensor_channel chan,
633 				  struct sensor_value *val)
634 {
635 	switch (chan) {
636 	case SENSOR_CHAN_ACCEL_X:
637 	case SENSOR_CHAN_ACCEL_Y:
638 	case SENSOR_CHAN_ACCEL_Z:
639 	case SENSOR_CHAN_ACCEL_XYZ:
640 		ism330dhcx_accel_channel_get(dev, chan, val);
641 		break;
642 	case SENSOR_CHAN_GYRO_X:
643 	case SENSOR_CHAN_GYRO_Y:
644 	case SENSOR_CHAN_GYRO_Z:
645 	case SENSOR_CHAN_GYRO_XYZ:
646 		ism330dhcx_gyro_channel_get(dev, chan, val);
647 		break;
648 #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP)
649 	case SENSOR_CHAN_DIE_TEMP:
650 		ism330dhcx_gyro_channel_get_temp(dev, val);
651 		break;
652 #endif
653 #if defined(CONFIG_ISM330DHCX_SENSORHUB)
654 	case SENSOR_CHAN_MAGN_X:
655 	case SENSOR_CHAN_MAGN_Y:
656 	case SENSOR_CHAN_MAGN_Z:
657 	case SENSOR_CHAN_MAGN_XYZ:
658 		ism330dhcx_magn_get_channel(dev, chan, val);
659 		break;
660 
661 	case SENSOR_CHAN_HUMIDITY:
662 		ism330dhcx_hum_convert(dev, val);
663 		break;
664 
665 	case SENSOR_CHAN_PRESS:
666 		ism330dhcx_press_convert(dev, val);
667 		break;
668 
669 	case SENSOR_CHAN_AMBIENT_TEMP:
670 		ism330dhcx_temp_convert(dev, val);
671 		break;
672 #endif
673 	default:
674 		return -ENOTSUP;
675 	}
676 
677 	return 0;
678 }
679 
680 static DEVICE_API(sensor, ism330dhcx_api_funcs) = {
681 	.attr_set = ism330dhcx_attr_set,
682 #if CONFIG_ISM330DHCX_TRIGGER
683 	.trigger_set = ism330dhcx_trigger_set,
684 #endif
685 	.sample_fetch = ism330dhcx_sample_fetch,
686 	.channel_get = ism330dhcx_channel_get,
687 };
688 
ism330dhcx_init_chip(const struct device * dev)689 static int ism330dhcx_init_chip(const struct device *dev)
690 {
691 	const struct ism330dhcx_config * const cfg = dev->config;
692 	struct ism330dhcx_data *ism330dhcx = dev->data;
693 	uint8_t chip_id;
694 
695 	ism330dhcx->dev = dev;
696 
697 	if (ism330dhcx_device_id_get(ism330dhcx->ctx, &chip_id) < 0) {
698 		LOG_DBG("Failed reading chip id");
699 		return -EIO;
700 	}
701 
702 	LOG_INF("chip id 0x%x", chip_id);
703 
704 	if (chip_id != ISM330DHCX_ID) {
705 		LOG_DBG("Invalid chip id 0x%x", chip_id);
706 		return -EIO;
707 	}
708 
709 	/* reset device */
710 	if (ism330dhcx_reset_set(ism330dhcx->ctx, 1) < 0) {
711 		return -EIO;
712 	}
713 
714 	k_busy_wait(100);
715 
716 	LOG_DBG("accel range is %d", cfg->accel_range);
717 	if (ism330dhcx_accel_range_set(dev, cfg->accel_range) < 0) {
718 		LOG_DBG("failed to set accelerometer full-scale");
719 		return -EIO;
720 	}
721 
722 	LOG_DBG("accel odr is %d", cfg->accel_odr);
723 	if (ism330dhcx_accel_set_odr_raw(dev, cfg->accel_odr) < 0) {
724 		LOG_DBG("failed to set accelerometer sampling rate");
725 		return -EIO;
726 	}
727 
728 	LOG_DBG("gyro range is %d", cfg->gyro_range);
729 	if (ism330dhcx_gyro_range_set(dev, cfg->gyro_range) < 0) {
730 		LOG_DBG("failed to set gyroscope full-scale");
731 		return -EIO;
732 	}
733 
734 	LOG_DBG("gyro odr is %d", cfg->gyro_odr);
735 	ism330dhcx->gyro_freq = ism330dhcx_odr_to_freq_val(cfg->gyro_odr);
736 	if (ism330dhcx_gyro_set_odr_raw(dev, cfg->gyro_odr) < 0) {
737 		LOG_DBG("failed to set gyroscope sampling rate");
738 		return -EIO;
739 	}
740 
741 	/* Set FIFO bypass mode */
742 	if (ism330dhcx_fifo_mode_set(ism330dhcx->ctx, ISM330DHCX_BYPASS_MODE) < 0) {
743 		LOG_DBG("failed to set FIFO mode");
744 		return -EIO;
745 	}
746 
747 	if (ism330dhcx_block_data_update_set(ism330dhcx->ctx, 1) < 0) {
748 		LOG_DBG("failed to set BDU mode");
749 		return -EIO;
750 	}
751 
752 	return 0;
753 }
754 
ism330dhcx_init(const struct device * dev)755 static int ism330dhcx_init(const struct device *dev)
756 {
757 	const struct ism330dhcx_config * const config = dev->config;
758 
759 	config->bus_init(dev);
760 
761 	if (ism330dhcx_init_chip(dev) < 0) {
762 		LOG_DBG("failed to initialize chip");
763 		return -EIO;
764 	}
765 
766 #ifdef CONFIG_ISM330DHCX_TRIGGER
767 	if (config->drdy_gpio.port) {
768 		if (ism330dhcx_init_interrupt(dev) < 0) {
769 			LOG_ERR("Failed to initialize interrupt.");
770 			return -EIO;
771 		}
772 	}
773 #endif
774 
775 #ifdef CONFIG_ISM330DHCX_SENSORHUB
776 	if (ism330dhcx_shub_init(dev) < 0) {
777 		LOG_DBG("failed to initialize external chip");
778 		return -EIO;
779 	}
780 #endif
781 
782 	return 0;
783 }
784 
785 #define ISM330DHCX_DEFINE(inst)									\
786 	static struct ism330dhcx_data ism330dhcx_data_##inst;					\
787 												\
788 	static const struct ism330dhcx_config ism330dhcx_config_##inst = {			\
789 		.accel_odr = DT_INST_PROP(inst, accel_odr),					\
790 		.accel_range = DT_INST_PROP(inst, accel_range),					\
791 		.gyro_odr = DT_INST_PROP(inst, gyro_odr),					\
792 		.gyro_range = DT_INST_PROP(inst, gyro_range),					\
793 		COND_CODE_1(DT_INST_ON_BUS(inst, spi),						\
794 			    (.bus_init = ism330dhcx_spi_init,					\
795 			     .spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER |		\
796 							 SPI_MODE_CPOL | SPI_MODE_CPHA |	\
797 							 SPI_WORD_SET(8), 0),),			\
798 			    ())									\
799 		COND_CODE_1(DT_INST_ON_BUS(inst, i2c),						\
800 			    (.bus_init = ism330dhcx_i2c_init,					\
801 			     .i2c = I2C_DT_SPEC_INST_GET(inst),),				\
802 			    ())									\
803 		IF_ENABLED(CONFIG_ISM330DHCX_TRIGGER,						\
804 			   (.drdy_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, drdy_gpios, { 0 }),	\
805 			    .int_pin = DT_INST_PROP_OR(inst, int_pin, 0),))			\
806 	};											\
807 												\
808 	SENSOR_DEVICE_DT_INST_DEFINE(inst, ism330dhcx_init, NULL,				\
809 			      &ism330dhcx_data_##inst, &ism330dhcx_config_##inst, POST_KERNEL,	\
810 			      CONFIG_SENSOR_INIT_PRIORITY, &ism330dhcx_api_funcs);		\
811 
812 DT_INST_FOREACH_STATUS_OKAY(ISM330DHCX_DEFINE)
813