1 /* ST Microelectronics LSM6DSO16IS 6-axis IMU sensor driver
2 *
3 * Copyright (c) 2023 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/lsm6dso16is.pdf
9 */
10
11 #define DT_DRV_COMPAT st_lsm6dso16is
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/logging/log.h>
20
21 #include "lsm6dso16is.h"
22
23 LOG_MODULE_REGISTER(LSM6DSO16IS, CONFIG_SENSOR_LOG_LEVEL);
24
25 static const uint16_t lsm6dso16is_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833,
26 1667, 3333, 6667};
27
lsm6dso16is_freq_to_odr_val(uint16_t freq)28 static int lsm6dso16is_freq_to_odr_val(uint16_t freq)
29 {
30 size_t i;
31
32 for (i = 0; i < ARRAY_SIZE(lsm6dso16is_odr_map); i++) {
33 if (freq <= lsm6dso16is_odr_map[i]) {
34 return i;
35 }
36 }
37
38 return -EINVAL;
39 }
40
lsm6dso16is_odr_to_freq_val(uint16_t odr)41 static int lsm6dso16is_odr_to_freq_val(uint16_t odr)
42 {
43 /* for valid index, return value from map */
44 if (odr < ARRAY_SIZE(lsm6dso16is_odr_map)) {
45 return lsm6dso16is_odr_map[odr & 0xF];
46 }
47
48 /* invalid index, return last entry */
49 return lsm6dso16is_odr_map[ARRAY_SIZE(lsm6dso16is_odr_map) - 1];
50 }
51
52 static const uint16_t lsm6dso16is_accel_fs_map[] = {2, 16, 4, 8};
53
lsm6dso16is_accel_range_to_fs_val(int32_t range)54 static int lsm6dso16is_accel_range_to_fs_val(int32_t range)
55 {
56 size_t i;
57
58 for (i = 0; i < ARRAY_SIZE(lsm6dso16is_accel_fs_map); i++) {
59 if (range == lsm6dso16is_accel_fs_map[i]) {
60 return i;
61 }
62 }
63
64 return -EINVAL;
65 }
66
67 static const uint16_t lsm6dso16is_gyro_fs_map[] = {250, 125, 500, 0, 1000, 0, 2000};
68 static const uint16_t lsm6dso16is_gyro_fs_sens[] = {2, 1, 4, 0, 8, 0, 16};
69
lsm6dso16is_gyro_range_to_fs_val(int32_t range)70 static int lsm6dso16is_gyro_range_to_fs_val(int32_t range)
71 {
72 size_t i;
73
74 for (i = 0; i < ARRAY_SIZE(lsm6dso16is_gyro_fs_map); i++) {
75 if (range == lsm6dso16is_gyro_fs_map[i]) {
76 return i;
77 }
78 }
79
80 return -EINVAL;
81 }
82
lsm6dso16is_reboot(const struct device * dev)83 static inline int lsm6dso16is_reboot(const struct device *dev)
84 {
85 const struct lsm6dso16is_config *cfg = dev->config;
86 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
87
88 if (lsm6dso16is_boot_set(ctx, 1) < 0) {
89 return -EIO;
90 }
91
92 /* Wait sensor turn-on time as per datasheet */
93 k_sleep(K_MSEC(35)); /* turn-on time in ms */
94
95 return 0;
96 }
97
lsm6dso16is_accel_set_fs_raw(const struct device * dev,uint8_t fs)98 static int lsm6dso16is_accel_set_fs_raw(const struct device *dev, uint8_t fs)
99 {
100 const struct lsm6dso16is_config *cfg = dev->config;
101 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
102 struct lsm6dso16is_data *data = dev->data;
103
104 if (lsm6dso16is_xl_full_scale_set(ctx, fs) < 0) {
105 return -EIO;
106 }
107
108 data->accel_fs = fs;
109
110 return 0;
111 }
112
lsm6dso16is_accel_set_odr_raw(const struct device * dev,uint8_t odr)113 static int lsm6dso16is_accel_set_odr_raw(const struct device *dev, uint8_t odr)
114 {
115 const struct lsm6dso16is_config *cfg = dev->config;
116 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
117 struct lsm6dso16is_data *data = dev->data;
118
119 if (lsm6dso16is_xl_data_rate_set(ctx, odr) < 0) {
120 return -EIO;
121 }
122
123 data->accel_freq = lsm6dso16is_odr_to_freq_val(odr);
124
125 return 0;
126 }
127
lsm6dso16is_gyro_set_fs_raw(const struct device * dev,uint8_t fs)128 static int lsm6dso16is_gyro_set_fs_raw(const struct device *dev, uint8_t fs)
129 {
130 const struct lsm6dso16is_config *cfg = dev->config;
131 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
132
133 if (lsm6dso16is_gy_full_scale_set(ctx, fs) < 0) {
134 return -EIO;
135 }
136
137 return 0;
138 }
139
lsm6dso16is_gyro_set_odr_raw(const struct device * dev,uint8_t odr)140 static int lsm6dso16is_gyro_set_odr_raw(const struct device *dev, uint8_t odr)
141 {
142 const struct lsm6dso16is_config *cfg = dev->config;
143 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
144
145 if (lsm6dso16is_gy_data_rate_set(ctx, odr) < 0) {
146 return -EIO;
147 }
148
149 return 0;
150 }
151
lsm6dso16is_accel_odr_set(const struct device * dev,uint16_t freq)152 static int lsm6dso16is_accel_odr_set(const struct device *dev, uint16_t freq)
153 {
154 int odr;
155
156 odr = lsm6dso16is_freq_to_odr_val(freq);
157 if (odr < 0) {
158 return odr;
159 }
160
161 if (lsm6dso16is_accel_set_odr_raw(dev, odr) < 0) {
162 LOG_DBG("failed to set accelerometer sampling rate");
163 return -EIO;
164 }
165
166 return 0;
167 }
168
lsm6dso16is_accel_range_set(const struct device * dev,int32_t range)169 static int lsm6dso16is_accel_range_set(const struct device *dev, int32_t range)
170 {
171 int fs;
172 struct lsm6dso16is_data *data = dev->data;
173
174 fs = lsm6dso16is_accel_range_to_fs_val(range);
175 if (fs < 0) {
176 return fs;
177 }
178
179 if (lsm6dso16is_accel_set_fs_raw(dev, fs) < 0) {
180 LOG_DBG("failed to set accelerometer full-scale");
181 return -EIO;
182 }
183
184 data->acc_gain = lsm6dso16is_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
185 return 0;
186 }
187
lsm6dso16is_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)188 static int lsm6dso16is_accel_config(const struct device *dev,
189 enum sensor_channel chan,
190 enum sensor_attribute attr,
191 const struct sensor_value *val)
192 {
193 const struct lsm6dso16is_config *cfg = dev->config;
194 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
195 lsm6dso16is_hm_mode_t mode;
196
197 switch (attr) {
198 case SENSOR_ATTR_FULL_SCALE:
199 return lsm6dso16is_accel_range_set(dev, sensor_ms2_to_g(val));
200 case SENSOR_ATTR_SAMPLING_FREQUENCY:
201 return lsm6dso16is_accel_odr_set(dev, val->val1);
202 case SENSOR_ATTR_CONFIGURATION:
203 switch (val->val1) {
204 case 0: /* High Performance */
205 mode = LSM6DSO16IS_HIGH_PERFOMANCE_MODE_ENABLED;
206 break;
207 case 1: /* Low Power */
208 mode = LSM6DSO16IS_HIGH_PERFOMANCE_MODE_DISABLED;
209 break;
210 default:
211 return -EIO;
212 }
213
214 return lsm6dso16is_xl_hm_mode_set(ctx, mode);
215 default:
216 LOG_DBG("Accel attribute not supported.");
217 return -ENOTSUP;
218 }
219
220 return 0;
221 }
222
lsm6dso16is_gyro_odr_set(const struct device * dev,uint16_t freq)223 static int lsm6dso16is_gyro_odr_set(const struct device *dev, uint16_t freq)
224 {
225 int odr;
226
227 odr = lsm6dso16is_freq_to_odr_val(freq);
228 if (odr < 0) {
229 return odr;
230 }
231
232 if (lsm6dso16is_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
lsm6dso16is_gyro_range_set(const struct device * dev,int32_t range)240 static int lsm6dso16is_gyro_range_set(const struct device *dev, int32_t range)
241 {
242 int fs;
243 struct lsm6dso16is_data *data = dev->data;
244
245 fs = lsm6dso16is_gyro_range_to_fs_val(range);
246 if (fs < 0) {
247 return fs;
248 }
249
250 if (lsm6dso16is_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 = (lsm6dso16is_gyro_fs_sens[fs] * GAIN_UNIT_G);
256 return 0;
257 }
258
lsm6dso16is_gyro_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)259 static int lsm6dso16is_gyro_config(const struct device *dev,
260 enum sensor_channel chan,
261 enum sensor_attribute attr,
262 const struct sensor_value *val)
263 {
264 const struct lsm6dso16is_config *cfg = dev->config;
265 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
266 lsm6dso16is_hm_mode_t mode;
267
268 switch (attr) {
269 case SENSOR_ATTR_FULL_SCALE:
270 return lsm6dso16is_gyro_range_set(dev, sensor_rad_to_degrees(val));
271 case SENSOR_ATTR_SAMPLING_FREQUENCY:
272 return lsm6dso16is_gyro_odr_set(dev, val->val1);
273 case SENSOR_ATTR_CONFIGURATION:
274 switch (val->val1) {
275 case 0: /* High Performance */
276 mode = LSM6DSO16IS_HIGH_PERFOMANCE_MODE_ENABLED;
277 break;
278 case 1: /* Low Power */
279 mode = LSM6DSO16IS_HIGH_PERFOMANCE_MODE_DISABLED;
280 break;
281 default:
282 return -EIO;
283 }
284
285 return lsm6dso16is_xl_hm_mode_set(ctx, mode);
286 default:
287 LOG_DBG("Gyro attribute not supported.");
288 return -ENOTSUP;
289 }
290
291 return 0;
292 }
293
lsm6dso16is_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)294 static int lsm6dso16is_attr_set(const struct device *dev,
295 enum sensor_channel chan,
296 enum sensor_attribute attr,
297 const struct sensor_value *val)
298 {
299 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
300 struct lsm6dso16is_data *data = dev->data;
301 #endif /* CONFIG_LSM6DSO16IS_SENSORHUB */
302
303 switch (chan) {
304 case SENSOR_CHAN_ACCEL_XYZ:
305 return lsm6dso16is_accel_config(dev, chan, attr, val);
306 case SENSOR_CHAN_GYRO_XYZ:
307 return lsm6dso16is_gyro_config(dev, chan, attr, val);
308 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
309 case SENSOR_CHAN_MAGN_XYZ:
310 case SENSOR_CHAN_PRESS:
311 case SENSOR_CHAN_HUMIDITY:
312 if (!data->shub_inited) {
313 LOG_ERR("shub not inited.");
314 return -ENOTSUP;
315 }
316
317 return lsm6dso16is_shub_config(dev, chan, attr, val);
318 #endif /* CONFIG_LSM6DSO16IS_SENSORHUB */
319 default:
320 LOG_WRN("attr_set() not supported on this channel.");
321 return -ENOTSUP;
322 }
323
324 return 0;
325 }
326
lsm6dso16is_sample_fetch_accel(const struct device * dev)327 static int lsm6dso16is_sample_fetch_accel(const struct device *dev)
328 {
329 const struct lsm6dso16is_config *cfg = dev->config;
330 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
331 struct lsm6dso16is_data *data = dev->data;
332
333 if (lsm6dso16is_acceleration_raw_get(ctx, data->acc) < 0) {
334 LOG_DBG("Failed to read sample");
335 return -EIO;
336 }
337
338 return 0;
339 }
340
lsm6dso16is_sample_fetch_gyro(const struct device * dev)341 static int lsm6dso16is_sample_fetch_gyro(const struct device *dev)
342 {
343 const struct lsm6dso16is_config *cfg = dev->config;
344 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
345 struct lsm6dso16is_data *data = dev->data;
346
347 if (lsm6dso16is_angular_rate_raw_get(ctx, data->gyro) < 0) {
348 LOG_DBG("Failed to read sample");
349 return -EIO;
350 }
351
352 return 0;
353 }
354
355 #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP)
lsm6dso16is_sample_fetch_temp(const struct device * dev)356 static int lsm6dso16is_sample_fetch_temp(const struct device *dev)
357 {
358 const struct lsm6dso16is_config *cfg = dev->config;
359 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
360 struct lsm6dso16is_data *data = dev->data;
361
362 if (lsm6dso16is_temperature_raw_get(ctx, &data->temp_sample) < 0) {
363 LOG_DBG("Failed to read sample");
364 return -EIO;
365 }
366
367 return 0;
368 }
369 #endif
370
371 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
lsm6dso16is_sample_fetch_shub(const struct device * dev)372 static int lsm6dso16is_sample_fetch_shub(const struct device *dev)
373 {
374 if (lsm6dso16is_shub_fetch_external_devs(dev) < 0) {
375 LOG_DBG("failed to read ext shub devices");
376 return -EIO;
377 }
378
379 return 0;
380 }
381 #endif /* CONFIG_LSM6DSO16IS_SENSORHUB */
382
lsm6dso16is_sample_fetch(const struct device * dev,enum sensor_channel chan)383 static int lsm6dso16is_sample_fetch(const struct device *dev,
384 enum sensor_channel chan)
385 {
386 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
387 struct lsm6dso16is_data *data = dev->data;
388 #endif /* CONFIG_LSM6DSO16IS_SENSORHUB */
389
390 switch (chan) {
391 case SENSOR_CHAN_ACCEL_XYZ:
392 lsm6dso16is_sample_fetch_accel(dev);
393 break;
394 case SENSOR_CHAN_GYRO_XYZ:
395 lsm6dso16is_sample_fetch_gyro(dev);
396 break;
397 #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP)
398 case SENSOR_CHAN_DIE_TEMP:
399 lsm6dso16is_sample_fetch_temp(dev);
400 break;
401 #endif
402 case SENSOR_CHAN_ALL:
403 lsm6dso16is_sample_fetch_accel(dev);
404 lsm6dso16is_sample_fetch_gyro(dev);
405 #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP)
406 lsm6dso16is_sample_fetch_temp(dev);
407 #endif
408 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
409 if (data->shub_inited) {
410 lsm6dso16is_sample_fetch_shub(dev);
411 }
412 #endif
413 break;
414 default:
415 return -ENOTSUP;
416 }
417
418 return 0;
419 }
420
lsm6dso16is_accel_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)421 static inline void lsm6dso16is_accel_convert(struct sensor_value *val, int raw_val,
422 uint32_t sensitivity)
423 {
424 int64_t dval;
425
426 /* Sensitivity is exposed in ug/LSB */
427 /* Convert to m/s^2 */
428 dval = (int64_t)(raw_val) * sensitivity;
429 sensor_ug_to_ms2(dval, val);
430
431 }
432
lsm6dso16is_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso16is_data * data,uint32_t sensitivity)433 static inline int lsm6dso16is_accel_get_channel(enum sensor_channel chan,
434 struct sensor_value *val,
435 struct lsm6dso16is_data *data,
436 uint32_t sensitivity)
437 {
438 uint8_t i;
439
440 switch (chan) {
441 case SENSOR_CHAN_ACCEL_X:
442 lsm6dso16is_accel_convert(val, data->acc[0], sensitivity);
443 break;
444 case SENSOR_CHAN_ACCEL_Y:
445 lsm6dso16is_accel_convert(val, data->acc[1], sensitivity);
446 break;
447 case SENSOR_CHAN_ACCEL_Z:
448 lsm6dso16is_accel_convert(val, data->acc[2], sensitivity);
449 break;
450 case SENSOR_CHAN_ACCEL_XYZ:
451 for (i = 0; i < 3; i++) {
452 lsm6dso16is_accel_convert(val++, data->acc[i], sensitivity);
453 }
454 break;
455 default:
456 return -ENOTSUP;
457 }
458
459 return 0;
460 }
461
lsm6dso16is_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso16is_data * data)462 static int lsm6dso16is_accel_channel_get(enum sensor_channel chan,
463 struct sensor_value *val,
464 struct lsm6dso16is_data *data)
465 {
466 return lsm6dso16is_accel_get_channel(chan, val, data, data->acc_gain);
467 }
468
lsm6dso16is_gyro_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)469 static inline void lsm6dso16is_gyro_convert(struct sensor_value *val, int raw_val,
470 uint32_t sensitivity)
471 {
472 int64_t dval;
473
474 /* Sensitivity is exposed in udps/LSB */
475 /* So, calculate value in 10 udps unit and then to rad/s */
476 dval = (int64_t)(raw_val) * sensitivity / 10;
477 sensor_10udegrees_to_rad(dval, val);
478 }
479
lsm6dso16is_gyro_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso16is_data * data,uint32_t sensitivity)480 static inline int lsm6dso16is_gyro_get_channel(enum sensor_channel chan,
481 struct sensor_value *val,
482 struct lsm6dso16is_data *data,
483 uint32_t sensitivity)
484 {
485 uint8_t i;
486
487 switch (chan) {
488 case SENSOR_CHAN_GYRO_X:
489 lsm6dso16is_gyro_convert(val, data->gyro[0], sensitivity);
490 break;
491 case SENSOR_CHAN_GYRO_Y:
492 lsm6dso16is_gyro_convert(val, data->gyro[1], sensitivity);
493 break;
494 case SENSOR_CHAN_GYRO_Z:
495 lsm6dso16is_gyro_convert(val, data->gyro[2], sensitivity);
496 break;
497 case SENSOR_CHAN_GYRO_XYZ:
498 for (i = 0; i < 3; i++) {
499 lsm6dso16is_gyro_convert(val++, data->gyro[i], sensitivity);
500 }
501 break;
502 default:
503 return -ENOTSUP;
504 }
505
506 return 0;
507 }
508
lsm6dso16is_gyro_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso16is_data * data)509 static int lsm6dso16is_gyro_channel_get(enum sensor_channel chan,
510 struct sensor_value *val,
511 struct lsm6dso16is_data *data)
512 {
513 return lsm6dso16is_gyro_get_channel(chan, val, data, data->gyro_gain);
514 }
515
516 #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP)
lsm6dso16is_gyro_channel_get_temp(struct sensor_value * val,struct lsm6dso16is_data * data)517 static void lsm6dso16is_gyro_channel_get_temp(struct sensor_value *val,
518 struct lsm6dso16is_data *data)
519 {
520 int32_t micro_c;
521
522 /* convert units to micro Celsius. Raw temperature samples are
523 * expressed in 256 LSB/deg_C units. And LSB output is 0 at 25 C.
524 */
525 micro_c = (data->temp_sample * 1000000) / 256;
526
527 val->val1 = micro_c / 1000000 + 25;
528 val->val2 = micro_c % 1000000;
529 }
530 #endif
531
532 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
lsm6dso16is_magn_convert(struct sensor_value * val,int raw_val,uint16_t sensitivity)533 static inline void lsm6dso16is_magn_convert(struct sensor_value *val, int raw_val,
534 uint16_t sensitivity)
535 {
536 double dval;
537
538 /* Sensitivity is exposed in ugauss/LSB */
539 dval = (double)(raw_val * sensitivity);
540 val->val1 = (int32_t)dval / 1000000;
541 val->val2 = (int32_t)dval % 1000000;
542 }
543
lsm6dso16is_magn_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dso16is_data * data)544 static inline int lsm6dso16is_magn_get_channel(enum sensor_channel chan,
545 struct sensor_value *val,
546 struct lsm6dso16is_data *data)
547 {
548 int16_t sample[3];
549 int idx;
550
551 idx = lsm6dso16is_shub_get_idx(data->dev, SENSOR_CHAN_MAGN_XYZ);
552 if (idx < 0) {
553 LOG_DBG("external magn not supported");
554 return -ENOTSUP;
555 }
556
557
558 sample[0] = (int16_t)(data->ext_data[idx][0] |
559 (data->ext_data[idx][1] << 8));
560 sample[1] = (int16_t)(data->ext_data[idx][2] |
561 (data->ext_data[idx][3] << 8));
562 sample[2] = (int16_t)(data->ext_data[idx][4] |
563 (data->ext_data[idx][5] << 8));
564
565 switch (chan) {
566 case SENSOR_CHAN_MAGN_X:
567 lsm6dso16is_magn_convert(val, sample[0], data->magn_gain);
568 break;
569 case SENSOR_CHAN_MAGN_Y:
570 lsm6dso16is_magn_convert(val, sample[1], data->magn_gain);
571 break;
572 case SENSOR_CHAN_MAGN_Z:
573 lsm6dso16is_magn_convert(val, sample[2], data->magn_gain);
574 break;
575 case SENSOR_CHAN_MAGN_XYZ:
576 lsm6dso16is_magn_convert(val, sample[0], data->magn_gain);
577 lsm6dso16is_magn_convert(val + 1, sample[1], data->magn_gain);
578 lsm6dso16is_magn_convert(val + 2, sample[2], data->magn_gain);
579 break;
580 default:
581 return -ENOTSUP;
582 }
583
584 return 0;
585 }
586
lsm6dso16is_hum_convert(struct sensor_value * val,struct lsm6dso16is_data * data)587 static inline void lsm6dso16is_hum_convert(struct sensor_value *val,
588 struct lsm6dso16is_data *data)
589 {
590 float rh;
591 int16_t raw_val;
592 struct hts221_data *ht = &data->hts221;
593 int idx;
594
595 idx = lsm6dso16is_shub_get_idx(data->dev, SENSOR_CHAN_HUMIDITY);
596 if (idx < 0) {
597 LOG_DBG("external press/temp not supported");
598 return;
599 }
600
601 raw_val = (int16_t)(data->ext_data[idx][0] |
602 (data->ext_data[idx][1] << 8));
603
604 /* find relative humidty by linear interpolation */
605 rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1;
606 rh /= (ht->x1 - ht->x0);
607
608 /* convert humidity to integer and fractional part */
609 val->val1 = rh;
610 val->val2 = rh * 1000000;
611 }
612
lsm6dso16is_press_convert(struct sensor_value * val,struct lsm6dso16is_data * data)613 static inline void lsm6dso16is_press_convert(struct sensor_value *val,
614 struct lsm6dso16is_data *data)
615 {
616 int32_t raw_val;
617 int idx;
618
619 idx = lsm6dso16is_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
620 if (idx < 0) {
621 LOG_DBG("external press/temp not supported");
622 return;
623 }
624
625 raw_val = (int32_t)(data->ext_data[idx][0] |
626 (data->ext_data[idx][1] << 8) |
627 (data->ext_data[idx][2] << 16));
628
629 /* Pressure sensitivity is 4096 LSB/hPa */
630 /* Convert raw_val to val in kPa */
631 val->val1 = (raw_val >> 12) / 10;
632 val->val2 = (raw_val >> 12) % 10 * 100000 +
633 (((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
634 }
635
lsm6dso16is_temp_convert(struct sensor_value * val,struct lsm6dso16is_data * data)636 static inline void lsm6dso16is_temp_convert(struct sensor_value *val,
637 struct lsm6dso16is_data *data)
638 {
639 int16_t raw_val;
640 int idx;
641
642 idx = lsm6dso16is_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
643 if (idx < 0) {
644 LOG_DBG("external press/temp not supported");
645 return;
646 }
647
648 raw_val = (int16_t)(data->ext_data[idx][3] |
649 (data->ext_data[idx][4] << 8));
650
651 /* Temperature sensitivity is 100 LSB/deg C */
652 val->val1 = raw_val / 100;
653 val->val2 = (int32_t)raw_val % 100 * (10000);
654 }
655 #endif
656
lsm6dso16is_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)657 static int lsm6dso16is_channel_get(const struct device *dev,
658 enum sensor_channel chan,
659 struct sensor_value *val)
660 {
661 struct lsm6dso16is_data *data = dev->data;
662
663 switch (chan) {
664 case SENSOR_CHAN_ACCEL_X:
665 case SENSOR_CHAN_ACCEL_Y:
666 case SENSOR_CHAN_ACCEL_Z:
667 case SENSOR_CHAN_ACCEL_XYZ:
668 lsm6dso16is_accel_channel_get(chan, val, data);
669 break;
670 case SENSOR_CHAN_GYRO_X:
671 case SENSOR_CHAN_GYRO_Y:
672 case SENSOR_CHAN_GYRO_Z:
673 case SENSOR_CHAN_GYRO_XYZ:
674 lsm6dso16is_gyro_channel_get(chan, val, data);
675 break;
676 #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP)
677 case SENSOR_CHAN_DIE_TEMP:
678 lsm6dso16is_gyro_channel_get_temp(val, data);
679 break;
680 #endif
681 #if defined(CONFIG_LSM6DSO16IS_SENSORHUB)
682 case SENSOR_CHAN_MAGN_X:
683 case SENSOR_CHAN_MAGN_Y:
684 case SENSOR_CHAN_MAGN_Z:
685 case SENSOR_CHAN_MAGN_XYZ:
686 if (!data->shub_inited) {
687 LOG_ERR("attr_set() shub not inited.");
688 return -ENOTSUP;
689 }
690
691 lsm6dso16is_magn_get_channel(chan, val, data);
692 break;
693
694 case SENSOR_CHAN_HUMIDITY:
695 if (!data->shub_inited) {
696 LOG_ERR("attr_set() shub not inited.");
697 return -ENOTSUP;
698 }
699
700 lsm6dso16is_hum_convert(val, data);
701 break;
702
703 case SENSOR_CHAN_PRESS:
704 if (!data->shub_inited) {
705 LOG_ERR("attr_set() shub not inited.");
706 return -ENOTSUP;
707 }
708
709 lsm6dso16is_press_convert(val, data);
710 break;
711
712 case SENSOR_CHAN_AMBIENT_TEMP:
713 if (!data->shub_inited) {
714 LOG_ERR("attr_set() shub not inited.");
715 return -ENOTSUP;
716 }
717
718 lsm6dso16is_temp_convert(val, data);
719 break;
720 #endif
721 default:
722 return -ENOTSUP;
723 }
724
725 return 0;
726 }
727
728 static DEVICE_API(sensor, lsm6dso16is_driver_api) = {
729 .attr_set = lsm6dso16is_attr_set,
730 #if CONFIG_LSM6DSO16IS_TRIGGER
731 .trigger_set = lsm6dso16is_trigger_set,
732 #endif
733 .sample_fetch = lsm6dso16is_sample_fetch,
734 .channel_get = lsm6dso16is_channel_get,
735 };
736
lsm6dso16is_init_chip(const struct device * dev)737 static int lsm6dso16is_init_chip(const struct device *dev)
738 {
739 const struct lsm6dso16is_config *cfg = dev->config;
740 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
741 struct lsm6dso16is_data *lsm6dso16is = dev->data;
742 uint8_t chip_id;
743 uint8_t odr, fs;
744
745 /* All registers except 0x01 are different between banks, including the WHO_AM_I
746 * register and the register used for a SW reset. If the lsm6dso16is wasn't on the user
747 * bank when it reset, then both the chip id check and the sw reset will fail unless we
748 * set the bank now.
749 */
750 if (lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_MAIN_MEM_BANK) < 0) {
751 LOG_DBG("Failed to set user bank");
752 return -EIO;
753 }
754
755 if (lsm6dso16is_device_id_get(ctx, &chip_id) < 0) {
756 LOG_DBG("Failed reading chip id");
757 return -EIO;
758 }
759
760 LOG_INF("chip id 0x%x", chip_id);
761
762 if (chip_id != LSM6DSO16IS_ID) {
763 LOG_DBG("Invalid chip id 0x%x", chip_id);
764 return -EIO;
765 }
766
767 /* reset device */
768 if (lsm6dso16is_software_reset(ctx) < 0) {
769 return -EIO;
770 }
771
772 fs = cfg->accel_range;
773 LOG_DBG("accel range is %d", fs);
774 if (lsm6dso16is_accel_set_fs_raw(dev, fs) < 0) {
775 LOG_ERR("failed to set accelerometer range %d", fs);
776 return -EIO;
777 }
778 lsm6dso16is->acc_gain = lsm6dso16is_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
779
780 odr = cfg->accel_odr;
781 LOG_DBG("accel odr is %d", odr);
782 if (lsm6dso16is_accel_set_odr_raw(dev, odr) < 0) {
783 LOG_ERR("failed to set accelerometer odr %d", odr);
784 return -EIO;
785 }
786
787 fs = cfg->gyro_range;
788 LOG_DBG("gyro range is %d", fs);
789 if (lsm6dso16is_gyro_set_fs_raw(dev, fs) < 0) {
790 LOG_ERR("failed to set gyroscope range %d", fs);
791 return -EIO;
792 }
793 lsm6dso16is->gyro_gain = (lsm6dso16is_gyro_fs_sens[fs] * GAIN_UNIT_G);
794
795 odr = cfg->gyro_odr;
796 LOG_DBG("gyro odr is %d", odr);
797 lsm6dso16is->gyro_freq = lsm6dso16is_odr_to_freq_val(odr);
798 if (lsm6dso16is_gyro_set_odr_raw(dev, odr) < 0) {
799 LOG_ERR("failed to set gyroscope odr %d", odr);
800 return -EIO;
801 }
802
803 if (lsm6dso16is_block_data_update_set(ctx, 1) < 0) {
804 LOG_DBG("failed to set BDU mode");
805 return -EIO;
806 }
807
808 return 0;
809 }
810
lsm6dso16is_init(const struct device * dev)811 static int lsm6dso16is_init(const struct device *dev)
812 {
813 #ifdef CONFIG_LSM6DSO16IS_TRIGGER
814 const struct lsm6dso16is_config *cfg = dev->config;
815 #endif
816 struct lsm6dso16is_data *data = dev->data;
817
818 LOG_INF("Initialize device %s", dev->name);
819 data->dev = dev;
820
821 if (lsm6dso16is_init_chip(dev) < 0) {
822 LOG_DBG("failed to initialize chip");
823 return -EIO;
824 }
825
826 #ifdef CONFIG_LSM6DSO16IS_TRIGGER
827 if (cfg->trig_enabled) {
828 if (lsm6dso16is_init_interrupt(dev) < 0) {
829 LOG_ERR("Failed to initialize interrupt.");
830 return -EIO;
831 }
832 }
833 #endif
834
835 #ifdef CONFIG_LSM6DSO16IS_SENSORHUB
836 data->shub_inited = true;
837 if (lsm6dso16is_shub_init(dev) < 0) {
838 LOG_INF("shub: no external chips found");
839 data->shub_inited = false;
840 }
841 #endif
842
843 return 0;
844 }
845
846 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
847 #warning "LSM6DSO16IS driver enabled without any devices"
848 #endif
849
850 /*
851 * Device creation macro, shared by LSM6DSO16IS_DEFINE_SPI() and
852 * LSM6DSO16IS_DEFINE_I2C().
853 */
854
855 #define LSM6DSO16IS_DEVICE_INIT(inst) \
856 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
857 lsm6dso16is_init, \
858 NULL, \
859 &lsm6dso16is_data_##inst, \
860 &lsm6dso16is_config_##inst, \
861 POST_KERNEL, \
862 CONFIG_SENSOR_INIT_PRIORITY, \
863 &lsm6dso16is_driver_api);
864
865 /*
866 * Instantiation macros used when a device is on a SPI bus.
867 */
868
869 #ifdef CONFIG_LSM6DSO16IS_TRIGGER
870 #define LSM6DSO16IS_CFG_IRQ(inst) \
871 .trig_enabled = true, \
872 .gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, irq_gpios), \
873 .drdy_pin = DT_INST_PROP(inst, drdy_pin)
874 #else
875 #define LSM6DSO16IS_CFG_IRQ(inst)
876 #endif /* CONFIG_LSM6DSO16IS_TRIGGER */
877
878 #define LSM6DSO16IS_SPI_OP (SPI_WORD_SET(8) | \
879 SPI_OP_MODE_MASTER | \
880 SPI_MODE_CPOL | \
881 SPI_MODE_CPHA) \
882
883 #define LSM6DSO16IS_CONFIG_COMMON(inst) \
884 .accel_odr = DT_INST_PROP(inst, accel_odr), \
885 .accel_range = DT_INST_PROP(inst, accel_range), \
886 .gyro_odr = DT_INST_PROP(inst, gyro_odr), \
887 .gyro_range = DT_INST_PROP(inst, gyro_range), \
888 .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \
889 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
890 (LSM6DSO16IS_CFG_IRQ(inst)), ())
891
892
893 #define LSM6DSO16IS_CONFIG_SPI(inst) \
894 { \
895 STMEMSC_CTX_SPI(&lsm6dso16is_config_##inst.stmemsc_cfg), \
896 .stmemsc_cfg = { \
897 .spi = SPI_DT_SPEC_INST_GET(inst, \
898 LSM6DSO16IS_SPI_OP, \
899 0), \
900 }, \
901 LSM6DSO16IS_CONFIG_COMMON(inst) \
902 }
903
904 /*
905 * Instantiation macros used when a device is on an I2C bus.
906 */
907
908 #define LSM6DSO16IS_CONFIG_I2C(inst) \
909 { \
910 STMEMSC_CTX_I2C(&lsm6dso16is_config_##inst.stmemsc_cfg), \
911 .stmemsc_cfg = { \
912 .i2c = I2C_DT_SPEC_INST_GET(inst), \
913 }, \
914 LSM6DSO16IS_CONFIG_COMMON(inst) \
915 }
916
917 /*
918 * Main instantiation macro. Use of COND_CODE_1() selects the right
919 * bus-specific macro at preprocessor time.
920 */
921
922 #define LSM6DSO16IS_DEFINE(inst) \
923 static struct lsm6dso16is_data lsm6dso16is_data_##inst; \
924 static const struct lsm6dso16is_config lsm6dso16is_config_##inst = \
925 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
926 (LSM6DSO16IS_CONFIG_SPI(inst)), \
927 (LSM6DSO16IS_CONFIG_I2C(inst))); \
928 LSM6DSO16IS_DEVICE_INIT(inst)
929
930 DT_INST_FOREACH_STATUS_OKAY(LSM6DSO16IS_DEFINE)
931