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