1 /* ST Microelectronics LSM6DSO 6-axis IMU sensor driver
2  *
3  * Copyright (c) 2019 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/lsm6dso.pdf
9  */
10 
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14 #include <zephyr/init.h>
15 #include <string.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/logging/log.h>
18 
19 #include "lsm6dso.h"
20 
21 LOG_MODULE_REGISTER(LSM6DSO, CONFIG_SENSOR_LOG_LEVEL);
22 
23 static const uint16_t lsm6dso_odr_map[] = {0, 12, 26, 52, 104, 208, 417, 833,
24 					1667, 3333, 6667};
25 
lsm6dso_freq_to_odr_val(uint16_t freq)26 static int lsm6dso_freq_to_odr_val(uint16_t freq)
27 {
28 	size_t i;
29 
30 	for (i = 0; i < ARRAY_SIZE(lsm6dso_odr_map); i++) {
31 		if (freq <= lsm6dso_odr_map[i]) {
32 			return i;
33 		}
34 	}
35 
36 	return -EINVAL;
37 }
38 
lsm6dso_odr_to_freq_val(uint16_t odr)39 static int lsm6dso_odr_to_freq_val(uint16_t odr)
40 {
41 	/* for valid index, return value from map */
42 	if (odr < ARRAY_SIZE(lsm6dso_odr_map)) {
43 		return lsm6dso_odr_map[odr];
44 	}
45 
46 	/* invalid index, return last entry */
47 	return lsm6dso_odr_map[ARRAY_SIZE(lsm6dso_odr_map) - 1];
48 }
49 
50 static const uint16_t lsm6dso_accel_fs_map[] = {2, 16, 4, 8};
51 
lsm6dso_accel_range_to_fs_val(int32_t range,bool double_range)52 static int lsm6dso_accel_range_to_fs_val(int32_t range, bool double_range)
53 {
54 	size_t i;
55 
56 	for (i = 0; i < ARRAY_SIZE(lsm6dso_accel_fs_map); i++) {
57 		if (range == (lsm6dso_accel_fs_map[i] << double_range)) {
58 			return i;
59 		}
60 	}
61 
62 	return -EINVAL;
63 }
64 
lsm6dso_accel_fs_val_to_gain(int fs,bool double_range)65 static int lsm6dso_accel_fs_val_to_gain(int fs, bool double_range)
66 {
67 	/* Range of ±2G has a LSB of GAIN_UNIT_XL, thus divide by 2 */
68 	return double_range ?
69 		lsm6dso_accel_fs_map[fs] * GAIN_UNIT_XL :
70 		lsm6dso_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
71 }
72 
73 static const uint16_t lsm6dso_gyro_fs_map[] = {250, 125, 500, 0, 1000, 0, 2000};
74 static const uint16_t lsm6dso_gyro_fs_sens[] = {2, 1, 4, 0, 8, 0, 16};
75 
lsm6dso_gyro_range_to_fs_val(int32_t range)76 static int lsm6dso_gyro_range_to_fs_val(int32_t range)
77 {
78 	size_t i;
79 
80 	for (i = 0; i < ARRAY_SIZE(lsm6dso_gyro_fs_map); i++) {
81 		if (range == lsm6dso_gyro_fs_map[i]) {
82 			return i;
83 		}
84 	}
85 
86 	return -EINVAL;
87 }
88 
lsm6dso_reboot(const struct device * dev)89 static inline int lsm6dso_reboot(const struct device *dev)
90 {
91 	const struct lsm6dso_config *cfg = dev->config;
92 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
93 
94 	if (lsm6dso_boot_set(ctx, 1) < 0) {
95 		return -EIO;
96 	}
97 
98 	/* Wait sensor turn-on time as per datasheet */
99 	k_busy_wait(35 * USEC_PER_MSEC);
100 
101 	return 0;
102 }
103 
lsm6dso_accel_set_fs_raw(const struct device * dev,uint8_t fs)104 static int lsm6dso_accel_set_fs_raw(const struct device *dev, uint8_t fs)
105 {
106 	const struct lsm6dso_config *cfg = dev->config;
107 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
108 	struct lsm6dso_data *data = dev->data;
109 
110 	if (lsm6dso_xl_full_scale_set(ctx, fs) < 0) {
111 		return -EIO;
112 	}
113 
114 	data->accel_fs = fs;
115 
116 	return 0;
117 }
118 
lsm6dso_accel_set_odr_raw(const struct device * dev,uint8_t odr)119 static int lsm6dso_accel_set_odr_raw(const struct device *dev, uint8_t odr)
120 {
121 	const struct lsm6dso_config *cfg = dev->config;
122 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
123 	struct lsm6dso_data *data = dev->data;
124 
125 	if (lsm6dso_xl_data_rate_set(ctx, odr) < 0) {
126 		return -EIO;
127 	}
128 
129 	data->accel_freq = lsm6dso_odr_to_freq_val(odr);
130 
131 	return 0;
132 }
133 
lsm6dso_gyro_set_fs_raw(const struct device * dev,uint8_t fs)134 static int lsm6dso_gyro_set_fs_raw(const struct device *dev, uint8_t fs)
135 {
136 	const struct lsm6dso_config *cfg = dev->config;
137 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
138 
139 	if (lsm6dso_gy_full_scale_set(ctx, fs) < 0) {
140 		return -EIO;
141 	}
142 
143 	return 0;
144 }
145 
lsm6dso_gyro_set_odr_raw(const struct device * dev,uint8_t odr)146 static int lsm6dso_gyro_set_odr_raw(const struct device *dev, uint8_t odr)
147 {
148 	const struct lsm6dso_config *cfg = dev->config;
149 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
150 
151 	if (lsm6dso_gy_data_rate_set(ctx, odr) < 0) {
152 		return -EIO;
153 	}
154 
155 	return 0;
156 }
157 
lsm6dso_accel_odr_set(const struct device * dev,uint16_t freq)158 static int lsm6dso_accel_odr_set(const struct device *dev, uint16_t freq)
159 {
160 	int odr;
161 
162 	odr = lsm6dso_freq_to_odr_val(freq);
163 	if (odr < 0) {
164 		return odr;
165 	}
166 
167 	if (lsm6dso_accel_set_odr_raw(dev, odr) < 0) {
168 		LOG_DBG("failed to set accelerometer sampling rate");
169 		return -EIO;
170 	}
171 
172 	return 0;
173 }
174 
lsm6dso_accel_range_set(const struct device * dev,int32_t range)175 static int lsm6dso_accel_range_set(const struct device *dev, int32_t range)
176 {
177 	int fs;
178 	struct lsm6dso_data *data = dev->data;
179 	const struct lsm6dso_config *cfg = dev->config;
180 	bool range_double = !!(cfg->accel_range & ACCEL_RANGE_DOUBLE);
181 
182 	fs = lsm6dso_accel_range_to_fs_val(range, range_double);
183 	if (fs < 0) {
184 		return fs;
185 	}
186 
187 	if (lsm6dso_accel_set_fs_raw(dev, fs) < 0) {
188 		LOG_DBG("failed to set accelerometer full-scale");
189 		return -EIO;
190 	}
191 
192 	data->acc_gain = lsm6dso_accel_fs_val_to_gain(fs, range_double);
193 	return 0;
194 }
195 
lsm6dso_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)196 static int lsm6dso_accel_config(const struct device *dev,
197 				enum sensor_channel chan,
198 				enum sensor_attribute attr,
199 				const struct sensor_value *val)
200 {
201 	switch (attr) {
202 	case SENSOR_ATTR_FULL_SCALE:
203 		return lsm6dso_accel_range_set(dev, sensor_ms2_to_g(val));
204 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
205 		return lsm6dso_accel_odr_set(dev, val->val1);
206 	default:
207 		LOG_DBG("Accel attribute not supported.");
208 		return -ENOTSUP;
209 	}
210 
211 	return 0;
212 }
213 
lsm6dso_gyro_odr_set(const struct device * dev,uint16_t freq)214 static int lsm6dso_gyro_odr_set(const struct device *dev, uint16_t freq)
215 {
216 	int odr;
217 
218 	odr = lsm6dso_freq_to_odr_val(freq);
219 	if (odr < 0) {
220 		return odr;
221 	}
222 
223 	if (lsm6dso_gyro_set_odr_raw(dev, odr) < 0) {
224 		LOG_DBG("failed to set gyroscope sampling rate");
225 		return -EIO;
226 	}
227 
228 	return 0;
229 }
230 
lsm6dso_gyro_range_set(const struct device * dev,int32_t range)231 static int lsm6dso_gyro_range_set(const struct device *dev, int32_t range)
232 {
233 	int fs;
234 	struct lsm6dso_data *data = dev->data;
235 
236 	fs = lsm6dso_gyro_range_to_fs_val(range);
237 	if (fs < 0) {
238 		return fs;
239 	}
240 
241 	if (lsm6dso_gyro_set_fs_raw(dev, fs) < 0) {
242 		LOG_DBG("failed to set gyroscope full-scale");
243 		return -EIO;
244 	}
245 
246 	data->gyro_gain = (lsm6dso_gyro_fs_sens[fs] * GAIN_UNIT_G);
247 	return 0;
248 }
249 
lsm6dso_gyro_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)250 static int lsm6dso_gyro_config(const struct device *dev,
251 			       enum sensor_channel chan,
252 			       enum sensor_attribute attr,
253 			       const struct sensor_value *val)
254 {
255 	switch (attr) {
256 	case SENSOR_ATTR_FULL_SCALE:
257 		return lsm6dso_gyro_range_set(dev, sensor_rad_to_degrees(val));
258 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
259 		return lsm6dso_gyro_odr_set(dev, val->val1);
260 	default:
261 		LOG_DBG("Gyro attribute not supported.");
262 		return -ENOTSUP;
263 	}
264 
265 	return 0;
266 }
267 
lsm6dso_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)268 static int lsm6dso_attr_set(const struct device *dev,
269 			    enum sensor_channel chan,
270 			    enum sensor_attribute attr,
271 			    const struct sensor_value *val)
272 {
273 #if defined(CONFIG_LSM6DSO_SENSORHUB)
274 	struct lsm6dso_data *data = dev->data;
275 #endif /* CONFIG_LSM6DSO_SENSORHUB */
276 
277 	switch (chan) {
278 	case SENSOR_CHAN_ACCEL_XYZ:
279 		return lsm6dso_accel_config(dev, chan, attr, val);
280 	case SENSOR_CHAN_GYRO_XYZ:
281 		return lsm6dso_gyro_config(dev, chan, attr, val);
282 #if defined(CONFIG_LSM6DSO_SENSORHUB)
283 	case SENSOR_CHAN_MAGN_XYZ:
284 	case SENSOR_CHAN_PRESS:
285 	case SENSOR_CHAN_HUMIDITY:
286 		if (!data->shub_inited) {
287 			LOG_ERR("shub not inited.");
288 			return -ENOTSUP;
289 		}
290 
291 		return lsm6dso_shub_config(dev, chan, attr, val);
292 #endif /* CONFIG_LSM6DSO_SENSORHUB */
293 	default:
294 		LOG_WRN("attr_set() not supported on this channel.");
295 		return -ENOTSUP;
296 	}
297 
298 	return 0;
299 }
300 
lsm6dso_sample_fetch_accel(const struct device * dev)301 static int lsm6dso_sample_fetch_accel(const struct device *dev)
302 {
303 	const struct lsm6dso_config *cfg = dev->config;
304 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
305 	struct lsm6dso_data *data = dev->data;
306 
307 	if (lsm6dso_acceleration_raw_get(ctx, data->acc) < 0) {
308 		LOG_DBG("Failed to read sample");
309 		return -EIO;
310 	}
311 
312 	return 0;
313 }
314 
lsm6dso_sample_fetch_gyro(const struct device * dev)315 static int lsm6dso_sample_fetch_gyro(const struct device *dev)
316 {
317 	const struct lsm6dso_config *cfg = dev->config;
318 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
319 	struct lsm6dso_data *data = dev->data;
320 
321 	if (lsm6dso_angular_rate_raw_get(ctx, data->gyro) < 0) {
322 		LOG_DBG("Failed to read sample");
323 		return -EIO;
324 	}
325 
326 	return 0;
327 }
328 
329 #if defined(CONFIG_LSM6DSO_ENABLE_TEMP)
lsm6dso_sample_fetch_temp(const struct device * dev)330 static int lsm6dso_sample_fetch_temp(const struct device *dev)
331 {
332 	const struct lsm6dso_config *cfg = dev->config;
333 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
334 	struct lsm6dso_data *data = dev->data;
335 
336 	if (lsm6dso_temperature_raw_get(ctx, &data->temp_sample) < 0) {
337 		LOG_DBG("Failed to read sample");
338 		return -EIO;
339 	}
340 
341 	return 0;
342 }
343 #endif
344 
345 #if defined(CONFIG_LSM6DSO_SENSORHUB)
lsm6dso_sample_fetch_shub(const struct device * dev)346 static int lsm6dso_sample_fetch_shub(const struct device *dev)
347 {
348 	if (lsm6dso_shub_fetch_external_devs(dev) < 0) {
349 		LOG_DBG("failed to read ext shub devices");
350 		return -EIO;
351 	}
352 
353 	return 0;
354 }
355 #endif /* CONFIG_LSM6DSO_SENSORHUB */
356 
lsm6dso_sample_fetch(const struct device * dev,enum sensor_channel chan)357 static int lsm6dso_sample_fetch(const struct device *dev,
358 				enum sensor_channel chan)
359 {
360 #if defined(CONFIG_LSM6DSO_SENSORHUB)
361 	struct lsm6dso_data *data = dev->data;
362 #endif /* CONFIG_LSM6DSO_SENSORHUB */
363 
364 	switch (chan) {
365 	case SENSOR_CHAN_ACCEL_XYZ:
366 		lsm6dso_sample_fetch_accel(dev);
367 		break;
368 	case SENSOR_CHAN_GYRO_XYZ:
369 		lsm6dso_sample_fetch_gyro(dev);
370 		break;
371 #if defined(CONFIG_LSM6DSO_ENABLE_TEMP)
372 	case SENSOR_CHAN_DIE_TEMP:
373 		lsm6dso_sample_fetch_temp(dev);
374 		break;
375 #endif
376 	case SENSOR_CHAN_ALL:
377 		lsm6dso_sample_fetch_accel(dev);
378 		lsm6dso_sample_fetch_gyro(dev);
379 #if defined(CONFIG_LSM6DSO_ENABLE_TEMP)
380 		lsm6dso_sample_fetch_temp(dev);
381 #endif
382 #if defined(CONFIG_LSM6DSO_SENSORHUB)
383 		if (data->shub_inited) {
384 			lsm6dso_sample_fetch_shub(dev);
385 		}
386 #endif
387 		break;
388 	default:
389 		return -ENOTSUP;
390 	}
391 
392 	return 0;
393 }
394 
lsm6dso_accel_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)395 static inline void lsm6dso_accel_convert(struct sensor_value *val, int raw_val,
396 					 uint32_t sensitivity)
397 {
398 	int64_t dval;
399 
400 	/* Sensitivity is exposed in ug/LSB */
401 	/* Convert to m/s^2 */
402 	dval = (int64_t)(raw_val) * sensitivity;
403 	sensor_ug_to_ms2(dval, val);
404 }
405 
lsm6dso_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso_data * data,uint32_t sensitivity)406 static inline int lsm6dso_accel_get_channel(enum sensor_channel chan,
407 					    struct sensor_value *val,
408 					    struct lsm6dso_data *data,
409 					    uint32_t sensitivity)
410 {
411 	uint8_t i;
412 
413 	switch (chan) {
414 	case SENSOR_CHAN_ACCEL_X:
415 		lsm6dso_accel_convert(val, data->acc[0], sensitivity);
416 		break;
417 	case SENSOR_CHAN_ACCEL_Y:
418 		lsm6dso_accel_convert(val, data->acc[1], sensitivity);
419 		break;
420 	case SENSOR_CHAN_ACCEL_Z:
421 		lsm6dso_accel_convert(val, data->acc[2], sensitivity);
422 		break;
423 	case SENSOR_CHAN_ACCEL_XYZ:
424 		for (i = 0; i < 3; i++) {
425 			lsm6dso_accel_convert(val++, data->acc[i], sensitivity);
426 		}
427 		break;
428 	default:
429 		return -ENOTSUP;
430 	}
431 
432 	return 0;
433 }
434 
lsm6dso_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso_data * data)435 static int lsm6dso_accel_channel_get(enum sensor_channel chan,
436 				     struct sensor_value *val,
437 				     struct lsm6dso_data *data)
438 {
439 	return lsm6dso_accel_get_channel(chan, val, data, data->acc_gain);
440 }
441 
lsm6dso_gyro_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)442 static inline void lsm6dso_gyro_convert(struct sensor_value *val, int raw_val,
443 					uint32_t sensitivity)
444 {
445 	int64_t dval;
446 
447 	/* Sensitivity is exposed in udps/LSB */
448 	/* So, calculate value in 10 udps unit and then to rad/s */
449 	dval = (int64_t)(raw_val) * sensitivity / 10;
450 	sensor_10udegrees_to_rad(dval, val);
451 }
452 
lsm6dso_gyro_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso_data * data,uint32_t sensitivity)453 static inline int lsm6dso_gyro_get_channel(enum sensor_channel chan,
454 					   struct sensor_value *val,
455 					   struct lsm6dso_data *data,
456 					   uint32_t sensitivity)
457 {
458 	uint8_t i;
459 
460 	switch (chan) {
461 	case SENSOR_CHAN_GYRO_X:
462 		lsm6dso_gyro_convert(val, data->gyro[0], sensitivity);
463 		break;
464 	case SENSOR_CHAN_GYRO_Y:
465 		lsm6dso_gyro_convert(val, data->gyro[1], sensitivity);
466 		break;
467 	case SENSOR_CHAN_GYRO_Z:
468 		lsm6dso_gyro_convert(val, data->gyro[2], sensitivity);
469 		break;
470 	case SENSOR_CHAN_GYRO_XYZ:
471 		for (i = 0; i < 3; i++) {
472 			lsm6dso_gyro_convert(val++, data->gyro[i], sensitivity);
473 		}
474 		break;
475 	default:
476 		return -ENOTSUP;
477 	}
478 
479 	return 0;
480 }
481 
lsm6dso_gyro_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso_data * data)482 static int lsm6dso_gyro_channel_get(enum sensor_channel chan,
483 				    struct sensor_value *val,
484 				    struct lsm6dso_data *data)
485 {
486 	return lsm6dso_gyro_get_channel(chan, val, data, data->gyro_gain);
487 }
488 
489 #if defined(CONFIG_LSM6DSO_ENABLE_TEMP)
lsm6dso_gyro_channel_get_temp(struct sensor_value * val,struct lsm6dso_data * data)490 static void lsm6dso_gyro_channel_get_temp(struct sensor_value *val,
491 					  struct lsm6dso_data *data)
492 {
493 	/* val = temp_sample / 256 + 25 */
494 	val->val1 = data->temp_sample / 256 + 25;
495 	val->val2 = (data->temp_sample % 256) * (1000000 / 256);
496 }
497 #endif
498 
499 #if defined(CONFIG_LSM6DSO_SENSORHUB)
lsm6dso_magn_convert(struct sensor_value * val,int raw_val,uint16_t sensitivity)500 static inline void lsm6dso_magn_convert(struct sensor_value *val, int raw_val,
501 					uint16_t sensitivity)
502 {
503 	double dval;
504 
505 	/* Sensitivity is exposed in ugauss/LSB */
506 	dval = (double)(raw_val * sensitivity);
507 	val->val1 = (int32_t)dval / 1000000;
508 	val->val2 = (int32_t)dval % 1000000;
509 }
510 
lsm6dso_magn_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso_data * data)511 static inline int lsm6dso_magn_get_channel(enum sensor_channel chan,
512 					   struct sensor_value *val,
513 					   struct lsm6dso_data *data)
514 {
515 	int16_t sample[3];
516 	int idx;
517 
518 	idx = lsm6dso_shub_get_idx(data->dev, SENSOR_CHAN_MAGN_XYZ);
519 	if (idx < 0) {
520 		LOG_DBG("external magn not supported");
521 		return -ENOTSUP;
522 	}
523 
524 
525 	sample[0] = (int16_t)(data->ext_data[idx][0] |
526 			     (data->ext_data[idx][1] << 8));
527 	sample[1] = (int16_t)(data->ext_data[idx][2] |
528 			     (data->ext_data[idx][3] << 8));
529 	sample[2] = (int16_t)(data->ext_data[idx][4] |
530 			     (data->ext_data[idx][5] << 8));
531 
532 	switch (chan) {
533 	case SENSOR_CHAN_MAGN_X:
534 		lsm6dso_magn_convert(val, sample[0], data->magn_gain);
535 		break;
536 	case SENSOR_CHAN_MAGN_Y:
537 		lsm6dso_magn_convert(val, sample[1], data->magn_gain);
538 		break;
539 	case SENSOR_CHAN_MAGN_Z:
540 		lsm6dso_magn_convert(val, sample[2], data->magn_gain);
541 		break;
542 	case SENSOR_CHAN_MAGN_XYZ:
543 		lsm6dso_magn_convert(val, sample[0], data->magn_gain);
544 		lsm6dso_magn_convert(val + 1, sample[1], data->magn_gain);
545 		lsm6dso_magn_convert(val + 2, sample[2], data->magn_gain);
546 		break;
547 	default:
548 		return -ENOTSUP;
549 	}
550 
551 	return 0;
552 }
553 
lsm6dso_hum_convert(struct sensor_value * val,struct lsm6dso_data * data)554 static inline void lsm6dso_hum_convert(struct sensor_value *val,
555 				       struct lsm6dso_data *data)
556 {
557 	float rh;
558 	int16_t raw_val;
559 	struct hts221_data *ht = &data->hts221;
560 	int idx;
561 
562 	idx = lsm6dso_shub_get_idx(data->dev, SENSOR_CHAN_HUMIDITY);
563 	if (idx < 0) {
564 		LOG_DBG("external press/temp not supported");
565 		return;
566 	}
567 
568 	raw_val = (int16_t)(data->ext_data[idx][0] |
569 			   (data->ext_data[idx][1] << 8));
570 
571 	/* find relative humidty by linear interpolation */
572 	rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1;
573 	rh /= (ht->x1 - ht->x0);
574 
575 	/* convert humidity to integer and fractional part */
576 	val->val1 = rh;
577 	val->val2 = rh * 1000000;
578 }
579 
lsm6dso_press_convert(struct sensor_value * val,struct lsm6dso_data * data)580 static inline void lsm6dso_press_convert(struct sensor_value *val,
581 					 struct lsm6dso_data *data)
582 {
583 	int32_t raw_val;
584 	int idx;
585 
586 	idx = lsm6dso_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
587 	if (idx < 0) {
588 		LOG_DBG("external press/temp not supported");
589 		return;
590 	}
591 
592 	raw_val = (int32_t)(data->ext_data[idx][0] |
593 			   (data->ext_data[idx][1] << 8) |
594 			   (data->ext_data[idx][2] << 16));
595 
596 	/* Pressure sensitivity is 4096 LSB/hPa */
597 	/* Convert raw_val to val in kPa */
598 	val->val1 = (raw_val >> 12) / 10;
599 	val->val2 = (raw_val >> 12) % 10 * 100000 +
600 		(((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
601 }
602 
lsm6dso_temp_convert(struct sensor_value * val,struct lsm6dso_data * data)603 static inline void lsm6dso_temp_convert(struct sensor_value *val,
604 					struct lsm6dso_data *data)
605 {
606 	int16_t raw_val;
607 	int idx;
608 
609 	idx = lsm6dso_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
610 	if (idx < 0) {
611 		LOG_DBG("external press/temp not supported");
612 		return;
613 	}
614 
615 	raw_val = (int16_t)(data->ext_data[idx][3] |
616 			   (data->ext_data[idx][4] << 8));
617 
618 	/* Temperature sensitivity is 100 LSB/deg C */
619 	val->val1 = raw_val / 100;
620 	val->val2 = (int32_t)raw_val % 100 * (10000);
621 }
622 #endif
623 
lsm6dso_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)624 static int lsm6dso_channel_get(const struct device *dev,
625 			       enum sensor_channel chan,
626 			       struct sensor_value *val)
627 {
628 	struct lsm6dso_data *data = dev->data;
629 
630 	switch (chan) {
631 	case SENSOR_CHAN_ACCEL_X:
632 	case SENSOR_CHAN_ACCEL_Y:
633 	case SENSOR_CHAN_ACCEL_Z:
634 	case SENSOR_CHAN_ACCEL_XYZ:
635 		lsm6dso_accel_channel_get(chan, val, data);
636 		break;
637 	case SENSOR_CHAN_GYRO_X:
638 	case SENSOR_CHAN_GYRO_Y:
639 	case SENSOR_CHAN_GYRO_Z:
640 	case SENSOR_CHAN_GYRO_XYZ:
641 		lsm6dso_gyro_channel_get(chan, val, data);
642 		break;
643 #if defined(CONFIG_LSM6DSO_ENABLE_TEMP)
644 	case SENSOR_CHAN_DIE_TEMP:
645 		lsm6dso_gyro_channel_get_temp(val, data);
646 		break;
647 #endif
648 #if defined(CONFIG_LSM6DSO_SENSORHUB)
649 	case SENSOR_CHAN_MAGN_X:
650 	case SENSOR_CHAN_MAGN_Y:
651 	case SENSOR_CHAN_MAGN_Z:
652 	case SENSOR_CHAN_MAGN_XYZ:
653 		if (!data->shub_inited) {
654 			LOG_ERR("attr_set() shub not inited.");
655 			return -ENOTSUP;
656 		}
657 
658 		lsm6dso_magn_get_channel(chan, val, data);
659 		break;
660 
661 	case SENSOR_CHAN_HUMIDITY:
662 		if (!data->shub_inited) {
663 			LOG_ERR("attr_set() shub not inited.");
664 			return -ENOTSUP;
665 		}
666 
667 		lsm6dso_hum_convert(val, data);
668 		break;
669 
670 	case SENSOR_CHAN_PRESS:
671 		if (!data->shub_inited) {
672 			LOG_ERR("attr_set() shub not inited.");
673 			return -ENOTSUP;
674 		}
675 
676 		lsm6dso_press_convert(val, data);
677 		break;
678 
679 	case SENSOR_CHAN_AMBIENT_TEMP:
680 		if (!data->shub_inited) {
681 			LOG_ERR("attr_set() shub not inited.");
682 			return -ENOTSUP;
683 		}
684 
685 		lsm6dso_temp_convert(val, data);
686 		break;
687 #endif
688 	default:
689 		return -ENOTSUP;
690 	}
691 
692 	return 0;
693 }
694 
695 static DEVICE_API(sensor, lsm6dso_driver_api) = {
696 	.attr_set = lsm6dso_attr_set,
697 #if CONFIG_LSM6DSO_TRIGGER
698 	.trigger_set = lsm6dso_trigger_set,
699 #endif
700 	.sample_fetch = lsm6dso_sample_fetch,
701 	.channel_get = lsm6dso_channel_get,
702 };
703 
lsm6dso_init_chip(const struct device * dev)704 static int lsm6dso_init_chip(const struct device *dev)
705 {
706 	const struct lsm6dso_config *cfg = dev->config;
707 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
708 	struct lsm6dso_data *lsm6dso = dev->data;
709 	uint8_t chip_id, master_on;
710 	uint8_t odr, fs;
711 
712 	/* All registers except 0x01 are different between banks, including the WHO_AM_I
713 	 * register and the register used for a SW reset.  If the lsm6dso wasn't on the user
714 	 * bank when it reset, then both the chip id check and the sw reset will fail unless we
715 	 * set the bank now.
716 	 */
717 	if (lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK) < 0) {
718 		LOG_DBG("Failed to set user bank");
719 		return -EIO;
720 	}
721 
722 	if (lsm6dso_device_id_get(ctx, &chip_id) < 0) {
723 		LOG_DBG("Failed reading chip id");
724 		return -EIO;
725 	}
726 
727 	LOG_INF("chip id 0x%x", chip_id);
728 
729 	if (chip_id != LSM6DSO_ID) {
730 		LOG_DBG("Invalid chip id 0x%x", chip_id);
731 		return -EIO;
732 	}
733 
734 	/* I3C disable stay preserved after s/w reset */
735 	if (lsm6dso_i3c_disable_set(ctx, LSM6DSO_I3C_DISABLE) < 0) {
736 		LOG_DBG("Failed to disable I3C");
737 		return -EIO;
738 	}
739 
740 	/* Per AN5192 §7.2.1, "… when applying the software reset procedure, the I2C master
741 	 * must be disabled, followed by a 300 μs wait."
742 	 */
743 	if (lsm6dso_sh_master_get(ctx, &master_on) < 0) {
744 		LOG_DBG("Failed to get I2C_MASTER status");
745 		return -EIO;
746 	}
747 	if (master_on) {
748 		LOG_DBG("Disable shub before reset");
749 		lsm6dso_sh_master_set(ctx, 0);
750 		k_busy_wait(300);
751 	}
752 
753 	/* reset device */
754 	if (lsm6dso_reset_set(ctx, 1) < 0) {
755 		return -EIO;
756 	}
757 
758 	k_busy_wait(100);
759 
760 	/* set accel power mode */
761 	LOG_DBG("accel pm is %d", cfg->accel_pm);
762 	switch (cfg->accel_pm) {
763 	default:
764 	case 0:
765 		lsm6dso_xl_power_mode_set(ctx, LSM6DSO_HIGH_PERFORMANCE_MD);
766 		break;
767 	case 1:
768 		lsm6dso_xl_power_mode_set(ctx, LSM6DSO_LOW_NORMAL_POWER_MD);
769 		break;
770 	case 2:
771 		lsm6dso_xl_power_mode_set(ctx, LSM6DSO_ULTRA_LOW_POWER_MD);
772 		break;
773 	}
774 
775 	fs = cfg->accel_range & ACCEL_RANGE_MASK;
776 	LOG_DBG("accel range is %d", fs);
777 	if (lsm6dso_accel_set_fs_raw(dev, fs) < 0) {
778 		LOG_ERR("failed to set accelerometer range %d", fs);
779 		return -EIO;
780 	}
781 	lsm6dso->acc_gain = lsm6dso_accel_fs_val_to_gain(fs, cfg->accel_range & ACCEL_RANGE_DOUBLE);
782 
783 	odr = cfg->accel_odr;
784 	LOG_DBG("accel odr is %d", odr);
785 	lsm6dso->accel_freq = lsm6dso_odr_to_freq_val(odr);
786 	if (lsm6dso_accel_set_odr_raw(dev, odr) < 0) {
787 		LOG_ERR("failed to set accelerometer odr %d", odr);
788 		return -EIO;
789 	}
790 
791 	/* set gyro power mode */
792 	LOG_DBG("gyro pm is %d", cfg->gyro_pm);
793 	switch (cfg->gyro_pm) {
794 	default:
795 	case 0:
796 		lsm6dso_gy_power_mode_set(ctx, LSM6DSO_GY_HIGH_PERFORMANCE);
797 		break;
798 	case 1:
799 		lsm6dso_gy_power_mode_set(ctx, LSM6DSO_GY_NORMAL);
800 		break;
801 	}
802 
803 	fs = cfg->gyro_range;
804 	LOG_DBG("gyro range is %d", fs);
805 	if (lsm6dso_gyro_set_fs_raw(dev, fs) < 0) {
806 		LOG_ERR("failed to set gyroscope range %d", fs);
807 		return -EIO;
808 	}
809 	lsm6dso->gyro_gain = (lsm6dso_gyro_fs_sens[fs] * GAIN_UNIT_G);
810 
811 	odr = cfg->gyro_odr;
812 	LOG_DBG("gyro odr is %d", odr);
813 	lsm6dso->gyro_freq = lsm6dso_odr_to_freq_val(odr);
814 	if (lsm6dso_gyro_set_odr_raw(dev, odr) < 0) {
815 		LOG_ERR("failed to set gyroscope odr %d", odr);
816 		return -EIO;
817 	}
818 
819 	/* Set FIFO bypass mode */
820 	if (lsm6dso_fifo_mode_set(ctx, LSM6DSO_BYPASS_MODE) < 0) {
821 		LOG_DBG("failed to set FIFO mode");
822 		return -EIO;
823 	}
824 
825 	if (lsm6dso_block_data_update_set(ctx, 1) < 0) {
826 		LOG_DBG("failed to set BDU mode");
827 		return -EIO;
828 	}
829 
830 	return 0;
831 }
832 
lsm6dso_init(const struct device * dev)833 static int lsm6dso_init(const struct device *dev)
834 {
835 #ifdef CONFIG_LSM6DSO_TRIGGER
836 	const struct lsm6dso_config *cfg = dev->config;
837 #endif
838 	struct lsm6dso_data *data = dev->data;
839 
840 	LOG_INF("Initialize device %s", dev->name);
841 	data->dev = dev;
842 
843 	if (lsm6dso_init_chip(dev) < 0) {
844 		LOG_DBG("failed to initialize chip");
845 		return -EIO;
846 	}
847 
848 #ifdef CONFIG_LSM6DSO_TRIGGER
849 	if (cfg->trig_enabled) {
850 		if (lsm6dso_init_interrupt(dev) < 0) {
851 			LOG_ERR("Failed to initialize interrupt.");
852 			return -EIO;
853 		}
854 	}
855 #endif
856 
857 #ifdef CONFIG_LSM6DSO_SENSORHUB
858 	data->shub_inited = true;
859 	if (lsm6dso_shub_init(dev) < 0) {
860 		LOG_INF("shub: no external chips found");
861 		data->shub_inited = false;
862 	}
863 #endif
864 
865 	return 0;
866 }
867 
868 /*
869  * Device creation macro, shared by LSM6DSO_DEFINE_SPI() and
870  * LSM6DSO_DEFINE_I2C().
871  */
872 
873 #define LSM6DSO_DEVICE_INIT(inst, model)				\
874 	SENSOR_DEVICE_DT_INST_DEFINE(inst,				\
875 			    lsm6dso_init,				\
876 			    NULL,					\
877 			    &model##_data_##inst,			\
878 			    &model##_config_##inst,			\
879 			    POST_KERNEL,				\
880 			    CONFIG_SENSOR_INIT_PRIORITY,		\
881 			    &lsm6dso_driver_api);
882 
883 /*
884  * Instantiation macros used when a device is on a SPI bus.
885  */
886 
887 #ifdef CONFIG_LSM6DSO_TRIGGER
888 #define LSM6DSO_CFG_IRQ(inst)						\
889 	.trig_enabled = true,						\
890 	.gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, irq_gpios),		\
891 	.int_pin = DT_INST_PROP(inst, int_pin)
892 #else
893 #define LSM6DSO_CFG_IRQ(inst)
894 #endif /* CONFIG_LSM6DSO_TRIGGER */
895 
896 #define LSM6DSO_SPI_OP  (SPI_WORD_SET(8) |				\
897 			 SPI_OP_MODE_MASTER |				\
898 			 SPI_MODE_CPOL |				\
899 			 SPI_MODE_CPHA)					\
900 
901 #define LSM6DSO_CONFIG_COMMON(inst)					\
902 	.accel_pm = DT_INST_PROP(inst, accel_pm),			\
903 	.accel_odr = DT_INST_PROP(inst, accel_odr),			\
904 	.accel_range = DT_INST_PROP(inst, accel_range) |		\
905 		(DT_INST_NODE_HAS_COMPAT(inst, st_lsm6dso32) ?	        \
906 			ACCEL_RANGE_DOUBLE : 0),			\
907 	.gyro_pm = DT_INST_PROP(inst, gyro_pm),				\
908 	.gyro_odr = DT_INST_PROP(inst, gyro_odr),			\
909 	.gyro_range = DT_INST_PROP(inst, gyro_range),			\
910 	.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed),                 \
911 	COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios),		\
912 		(LSM6DSO_CFG_IRQ(inst)), ())
913 
914 #define LSM6DSO_CONFIG_SPI(inst, model)					\
915 	{								\
916 		STMEMSC_CTX_SPI(&model##_config_##inst.stmemsc_cfg),	\
917 		.stmemsc_cfg = {					\
918 			.spi = SPI_DT_SPEC_INST_GET(inst,		\
919 					   LSM6DSO_SPI_OP,		\
920 					   0),				\
921 		},							\
922 		LSM6DSO_CONFIG_COMMON(inst)				\
923 	}
924 
925 /*
926  * Instantiation macros used when a device is on an I2C bus.
927  */
928 
929 #define LSM6DSO_CONFIG_I2C(inst, model)					\
930 	{								\
931 		STMEMSC_CTX_I2C(&model##_config_##inst.stmemsc_cfg),	\
932 		.stmemsc_cfg = {					\
933 			.i2c = I2C_DT_SPEC_INST_GET(inst),		\
934 		},							\
935 		LSM6DSO_CONFIG_COMMON(inst)				\
936 	}
937 
938 /*
939  * Main instantiation macro. Use of COND_CODE_1() selects the right
940  * bus-specific macro at preprocessor time.
941  */
942 
943 #define LSM6DSO_DEFINE(inst, model)					\
944 	static struct lsm6dso_data model##_data_##inst;			\
945 	static const struct lsm6dso_config model##_config_##inst =	\
946 		COND_CODE_1(DT_INST_ON_BUS(inst, spi),			\
947 			(LSM6DSO_CONFIG_SPI(inst, model)),		\
948 			(LSM6DSO_CONFIG_I2C(inst, model)));		\
949 	LSM6DSO_DEVICE_INIT(inst, model)
950 
951 #define DT_DRV_COMPAT st_lsm6dso
952 DT_INST_FOREACH_STATUS_OKAY_VARGS(LSM6DSO_DEFINE, lsm6dso)
953 #undef DT_DRV_COMPAT
954 
955 #define DT_DRV_COMPAT st_lsm6dso32
956 DT_INST_FOREACH_STATUS_OKAY_VARGS(LSM6DSO_DEFINE, lsm6dso32)
957 #undef DT_DRV_COMPAT
958