1 /* lsm6dsl.c - Driver for LSM6DSL accelerometer, gyroscope and
2 * temperature sensor
3 */
4
5 /*
6 * Copyright (c) 2017 Linaro Limited
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #define DT_DRV_COMPAT st_lsm6dsl
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/byteorder.h>
19 #include <zephyr/sys/__assert.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/pm/device.h>
22
23 #include "lsm6dsl.h"
24
25 LOG_MODULE_REGISTER(LSM6DSL, CONFIG_SENSOR_LOG_LEVEL);
26
27 static const uint16_t lsm6dsl_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833,
28 1666, 3332, 6664, 1};
29
30 #if defined(LSM6DSL_ACCEL_ODR_RUNTIME) || defined(LSM6DSL_GYRO_ODR_RUNTIME) ||\
31 defined(CONFIG_PM_DEVICE)
lsm6dsl_freq_to_odr_val(uint16_t freq)32 static int lsm6dsl_freq_to_odr_val(uint16_t freq)
33 {
34 size_t i;
35
36 for (i = 0; i < ARRAY_SIZE(lsm6dsl_odr_map); i++) {
37 if (freq == lsm6dsl_odr_map[i]) {
38 return i;
39 }
40 }
41
42 return -EINVAL;
43 }
44 #endif
45
lsm6dsl_odr_to_freq_val(uint16_t odr)46 static int lsm6dsl_odr_to_freq_val(uint16_t odr)
47 {
48 /* for valid index, return value from map */
49 if (odr < ARRAY_SIZE(lsm6dsl_odr_map)) {
50 return lsm6dsl_odr_map[odr];
51 }
52
53 /* invalid index, return the fastest entry (6.66kHz) */
54 BUILD_ASSERT(ARRAY_SIZE(lsm6dsl_odr_map) > 10);
55 return lsm6dsl_odr_map[10];
56 }
57
58 #ifdef LSM6DSL_ACCEL_FS_RUNTIME
59 static const uint16_t lsm6dsl_accel_fs_map[] = {2, 16, 4, 8};
60 static const uint16_t lsm6dsl_accel_fs_sens[] = {1, 8, 2, 4};
61
lsm6dsl_accel_range_to_fs_val(int32_t range)62 static int lsm6dsl_accel_range_to_fs_val(int32_t range)
63 {
64 size_t i;
65
66 for (i = 0; i < ARRAY_SIZE(lsm6dsl_accel_fs_map); i++) {
67 if (range == lsm6dsl_accel_fs_map[i]) {
68 return i;
69 }
70 }
71
72 return -EINVAL;
73 }
74 #endif
75
76 #ifdef LSM6DSL_GYRO_FS_RUNTIME
77 static const uint16_t lsm6dsl_gyro_fs_map[] = {250, 500, 1000, 2000, 125};
78 static const uint16_t lsm6dsl_gyro_fs_sens[] = {2, 4, 8, 16, 1};
79
lsm6dsl_gyro_range_to_fs_val(int32_t range)80 static int lsm6dsl_gyro_range_to_fs_val(int32_t range)
81 {
82 size_t i;
83
84 for (i = 0; i < ARRAY_SIZE(lsm6dsl_gyro_fs_map); i++) {
85 if (range == lsm6dsl_gyro_fs_map[i]) {
86 return i;
87 }
88 }
89
90 return -EINVAL;
91 }
92 #endif
93
lsm6dsl_reboot(const struct device * dev)94 static inline int lsm6dsl_reboot(const struct device *dev)
95 {
96 struct lsm6dsl_data *data = dev->data;
97
98 if (data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL3_C,
99 LSM6DSL_MASK_CTRL3_C_BOOT,
100 1 << LSM6DSL_SHIFT_CTRL3_C_BOOT) < 0) {
101 return -EIO;
102 }
103
104 /* Wait sensor turn-on time as per datasheet */
105 k_busy_wait(USEC_PER_MSEC * 35U);
106
107 return 0;
108 }
109
lsm6dsl_accel_set_fs_raw(const struct device * dev,uint8_t fs)110 static int lsm6dsl_accel_set_fs_raw(const struct device *dev, uint8_t fs)
111 {
112 struct lsm6dsl_data *data = dev->data;
113
114 if (data->hw_tf->update_reg(dev,
115 LSM6DSL_REG_CTRL1_XL,
116 LSM6DSL_MASK_CTRL1_XL_FS_XL,
117 fs << LSM6DSL_SHIFT_CTRL1_XL_FS_XL) < 0) {
118 return -EIO;
119 }
120
121 return 0;
122 }
123
lsm6dsl_accel_set_odr_raw(const struct device * dev,uint8_t odr)124 static int lsm6dsl_accel_set_odr_raw(const struct device *dev, uint8_t odr)
125 {
126 struct lsm6dsl_data *data = dev->data;
127
128 if (data->hw_tf->update_reg(dev,
129 LSM6DSL_REG_CTRL1_XL,
130 LSM6DSL_MASK_CTRL1_XL_ODR_XL,
131 odr << LSM6DSL_SHIFT_CTRL1_XL_ODR_XL) < 0) {
132 return -EIO;
133 }
134
135 data->accel_freq = lsm6dsl_odr_to_freq_val(odr);
136
137 return 0;
138 }
139
lsm6dsl_gyro_set_fs_raw(const struct device * dev,uint8_t fs)140 static int lsm6dsl_gyro_set_fs_raw(const struct device *dev, uint8_t fs)
141 {
142 struct lsm6dsl_data *data = dev->data;
143
144 if (fs == GYRO_FULLSCALE_125) {
145 if (data->hw_tf->update_reg(dev,
146 LSM6DSL_REG_CTRL2_G,
147 LSM6DSL_MASK_CTRL2_FS125 | LSM6DSL_MASK_CTRL2_G_FS_G,
148 1 << LSM6DSL_SHIFT_CTRL2_FS125) < 0) {
149 return -EIO;
150 }
151 } else {
152 if (data->hw_tf->update_reg(dev,
153 LSM6DSL_REG_CTRL2_G,
154 LSM6DSL_MASK_CTRL2_FS125 | LSM6DSL_MASK_CTRL2_G_FS_G,
155 fs << LSM6DSL_SHIFT_CTRL2_G_FS_G) < 0) {
156 return -EIO;
157 }
158 }
159
160 return 0;
161 }
162
lsm6dsl_gyro_set_odr_raw(const struct device * dev,uint8_t odr)163 static int lsm6dsl_gyro_set_odr_raw(const struct device *dev, uint8_t odr)
164 {
165 struct lsm6dsl_data *data = dev->data;
166
167 if (data->hw_tf->update_reg(dev,
168 LSM6DSL_REG_CTRL2_G,
169 LSM6DSL_MASK_CTRL2_G_ODR_G,
170 odr << LSM6DSL_SHIFT_CTRL2_G_ODR_G) < 0) {
171 return -EIO;
172 }
173
174 data->gyro_freq = lsm6dsl_odr_to_freq_val(odr);
175
176 return 0;
177 }
178
179 #ifdef LSM6DSL_ACCEL_ODR_RUNTIME
lsm6dsl_accel_odr_set(const struct device * dev,uint16_t freq)180 static int lsm6dsl_accel_odr_set(const struct device *dev, uint16_t freq)
181 {
182 int odr;
183
184 odr = lsm6dsl_freq_to_odr_val(freq);
185 if (odr < 0) {
186 return odr;
187 }
188
189 if (lsm6dsl_accel_set_odr_raw(dev, odr) < 0) {
190 LOG_DBG("failed to set accelerometer sampling rate");
191 return -EIO;
192 }
193
194 return 0;
195 }
196 #endif
197
198 #ifdef LSM6DSL_ACCEL_FS_RUNTIME
lsm6dsl_accel_range_set(const struct device * dev,int32_t range)199 static int lsm6dsl_accel_range_set(const struct device *dev, int32_t range)
200 {
201 int fs;
202 struct lsm6dsl_data *data = dev->data;
203
204 fs = lsm6dsl_accel_range_to_fs_val(range);
205 if (fs < 0) {
206 return fs;
207 }
208
209 if (lsm6dsl_accel_set_fs_raw(dev, fs) < 0) {
210 LOG_DBG("failed to set accelerometer full-scale");
211 return -EIO;
212 }
213
214 data->accel_sensitivity = (float)(lsm6dsl_accel_fs_sens[fs]
215 * SENSI_GRAIN_XL);
216 return 0;
217 }
218 #endif
219
lsm6dsl_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)220 static int lsm6dsl_accel_config(const struct device *dev,
221 enum sensor_channel chan,
222 enum sensor_attribute attr,
223 const struct sensor_value *val)
224 {
225 switch (attr) {
226 #ifdef LSM6DSL_ACCEL_FS_RUNTIME
227 case SENSOR_ATTR_FULL_SCALE:
228 return lsm6dsl_accel_range_set(dev, sensor_ms2_to_g(val));
229 #endif
230 #ifdef LSM6DSL_ACCEL_ODR_RUNTIME
231 case SENSOR_ATTR_SAMPLING_FREQUENCY:
232 return lsm6dsl_accel_odr_set(dev, val->val1);
233 #endif
234 default:
235 LOG_DBG("Accel attribute not supported.");
236 return -ENOTSUP;
237 }
238
239 return 0;
240 }
241
242 #ifdef LSM6DSL_GYRO_ODR_RUNTIME
lsm6dsl_gyro_odr_set(const struct device * dev,uint16_t freq)243 static int lsm6dsl_gyro_odr_set(const struct device *dev, uint16_t freq)
244 {
245 int odr;
246
247 odr = lsm6dsl_freq_to_odr_val(freq);
248 if (odr < 0) {
249 return odr;
250 }
251
252 if (lsm6dsl_gyro_set_odr_raw(dev, odr) < 0) {
253 LOG_DBG("failed to set gyroscope sampling rate");
254 return -EIO;
255 }
256
257 return 0;
258 }
259 #endif
260
261 #ifdef LSM6DSL_GYRO_FS_RUNTIME
lsm6dsl_gyro_range_set(const struct device * dev,int32_t range)262 static int lsm6dsl_gyro_range_set(const struct device *dev, int32_t range)
263 {
264 int fs;
265 struct lsm6dsl_data *data = dev->data;
266
267 fs = lsm6dsl_gyro_range_to_fs_val(range);
268 if (fs < 0) {
269 return fs;
270 }
271
272 if (lsm6dsl_gyro_set_fs_raw(dev, fs) < 0) {
273 LOG_DBG("failed to set gyroscope full-scale");
274 return -EIO;
275 }
276
277 data->gyro_sensitivity = (float)(lsm6dsl_gyro_fs_sens[fs]
278 * SENSI_GRAIN_G);
279 return 0;
280 }
281 #endif
282
lsm6dsl_gyro_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)283 static int lsm6dsl_gyro_config(const struct device *dev,
284 enum sensor_channel chan,
285 enum sensor_attribute attr,
286 const struct sensor_value *val)
287 {
288 switch (attr) {
289 #ifdef LSM6DSL_GYRO_FS_RUNTIME
290 case SENSOR_ATTR_FULL_SCALE:
291 return lsm6dsl_gyro_range_set(dev, sensor_rad_to_degrees(val));
292 #endif
293 #ifdef LSM6DSL_GYRO_ODR_RUNTIME
294 case SENSOR_ATTR_SAMPLING_FREQUENCY:
295 return lsm6dsl_gyro_odr_set(dev, val->val1);
296 #endif
297 default:
298 LOG_DBG("Gyro attribute not supported.");
299 return -ENOTSUP;
300 }
301
302 return 0;
303 }
304
lsm6dsl_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)305 static int lsm6dsl_attr_set(const struct device *dev,
306 enum sensor_channel chan,
307 enum sensor_attribute attr,
308 const struct sensor_value *val)
309 {
310 switch (chan) {
311 case SENSOR_CHAN_ACCEL_XYZ:
312 return lsm6dsl_accel_config(dev, chan, attr, val);
313 case SENSOR_CHAN_GYRO_XYZ:
314 return lsm6dsl_gyro_config(dev, chan, attr, val);
315 default:
316 LOG_WRN("attr_set() not supported on this channel.");
317 return -ENOTSUP;
318 }
319
320 return 0;
321 }
322
lsm6dsl_sample_fetch_accel(const struct device * dev)323 static int lsm6dsl_sample_fetch_accel(const struct device *dev)
324 {
325 struct lsm6dsl_data *data = dev->data;
326 uint8_t buf[6];
327
328 if (data->hw_tf->read_data(dev, LSM6DSL_REG_OUTX_L_XL,
329 buf, sizeof(buf)) < 0) {
330 LOG_DBG("failed to read sample");
331 return -EIO;
332 }
333
334 data->accel_sample_x = (int16_t)((uint16_t)(buf[0]) |
335 ((uint16_t)(buf[1]) << 8));
336 data->accel_sample_y = (int16_t)((uint16_t)(buf[2]) |
337 ((uint16_t)(buf[3]) << 8));
338 data->accel_sample_z = (int16_t)((uint16_t)(buf[4]) |
339 ((uint16_t)(buf[5]) << 8));
340
341 return 0;
342 }
343
lsm6dsl_sample_fetch_gyro(const struct device * dev)344 static int lsm6dsl_sample_fetch_gyro(const struct device *dev)
345 {
346 struct lsm6dsl_data *data = dev->data;
347 uint8_t buf[6];
348
349 if (data->hw_tf->read_data(dev, LSM6DSL_REG_OUTX_L_G,
350 buf, sizeof(buf)) < 0) {
351 LOG_DBG("failed to read sample");
352 return -EIO;
353 }
354
355 data->gyro_sample_x = (int16_t)((uint16_t)(buf[0]) |
356 ((uint16_t)(buf[1]) << 8));
357 data->gyro_sample_y = (int16_t)((uint16_t)(buf[2]) |
358 ((uint16_t)(buf[3]) << 8));
359 data->gyro_sample_z = (int16_t)((uint16_t)(buf[4]) |
360 ((uint16_t)(buf[5]) << 8));
361
362 return 0;
363 }
364
365 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
lsm6dsl_sample_fetch_temp(const struct device * dev)366 static int lsm6dsl_sample_fetch_temp(const struct device *dev)
367 {
368 struct lsm6dsl_data *data = dev->data;
369 uint8_t buf[2];
370
371 if (data->hw_tf->read_data(dev, LSM6DSL_REG_OUT_TEMP_L,
372 buf, sizeof(buf)) < 0) {
373 LOG_DBG("failed to read sample");
374 return -EIO;
375 }
376
377 data->temp_sample = (int16_t)((uint16_t)(buf[0]) |
378 ((uint16_t)(buf[1]) << 8));
379
380 return 0;
381 }
382 #endif
383
384 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
lsm6dsl_sample_fetch_magn(const struct device * dev)385 static int lsm6dsl_sample_fetch_magn(const struct device *dev)
386 {
387 struct lsm6dsl_data *data = dev->data;
388 uint8_t buf[6];
389
390 if (lsm6dsl_shub_read_external_chip(dev, buf, sizeof(buf)) < 0) {
391 LOG_DBG("failed to read ext mag sample");
392 return -EIO;
393 }
394
395 data->magn_sample_x = (int16_t)((uint16_t)(buf[0]) |
396 ((uint16_t)(buf[1]) << 8));
397 data->magn_sample_y = (int16_t)((uint16_t)(buf[2]) |
398 ((uint16_t)(buf[3]) << 8));
399 data->magn_sample_z = (int16_t)((uint16_t)(buf[4]) |
400 ((uint16_t)(buf[5]) << 8));
401
402 return 0;
403 }
404 #endif
405 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
lsm6dsl_sample_fetch_press(const struct device * dev)406 static int lsm6dsl_sample_fetch_press(const struct device *dev)
407 {
408 struct lsm6dsl_data *data = dev->data;
409 uint8_t buf[5];
410
411 if (lsm6dsl_shub_read_external_chip(dev, buf, sizeof(buf)) < 0) {
412 LOG_DBG("failed to read ext press sample");
413 return -EIO;
414 }
415
416 data->sample_press = (int32_t)((uint32_t)(buf[0]) |
417 ((uint32_t)(buf[1]) << 8) |
418 ((uint32_t)(buf[2]) << 16));
419 data->sample_temp = (int16_t)((uint16_t)(buf[3]) |
420 ((uint16_t)(buf[4]) << 8));
421
422 return 0;
423 }
424 #endif
425
lsm6dsl_sample_fetch(const struct device * dev,enum sensor_channel chan)426 static int lsm6dsl_sample_fetch(const struct device *dev,
427 enum sensor_channel chan)
428 {
429 switch (chan) {
430 case SENSOR_CHAN_ACCEL_XYZ:
431 lsm6dsl_sample_fetch_accel(dev);
432 break;
433 case SENSOR_CHAN_GYRO_XYZ:
434 lsm6dsl_sample_fetch_gyro(dev);
435 break;
436 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
437 case SENSOR_CHAN_DIE_TEMP:
438 lsm6dsl_sample_fetch_temp(dev);
439 break;
440 #endif
441 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
442 case SENSOR_CHAN_MAGN_XYZ:
443 lsm6dsl_sample_fetch_magn(dev);
444 break;
445 #endif
446 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
447 case SENSOR_CHAN_AMBIENT_TEMP:
448 case SENSOR_CHAN_PRESS:
449 lsm6dsl_sample_fetch_press(dev);
450 break;
451 #endif
452 case SENSOR_CHAN_ALL:
453 lsm6dsl_sample_fetch_accel(dev);
454 lsm6dsl_sample_fetch_gyro(dev);
455 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
456 lsm6dsl_sample_fetch_temp(dev);
457 #endif
458 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
459 lsm6dsl_sample_fetch_magn(dev);
460 #endif
461 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
462 lsm6dsl_sample_fetch_press(dev);
463 #endif
464 break;
465 default:
466 return -ENOTSUP;
467 }
468
469 return 0;
470 }
471
lsm6dsl_accel_convert(struct sensor_value * val,int raw_val,float sensitivity)472 static inline void lsm6dsl_accel_convert(struct sensor_value *val, int raw_val,
473 float sensitivity)
474 {
475 double dval;
476
477 /* Sensitivity is exposed in mg/LSB */
478 /* Convert to m/s^2 */
479 dval = (double)(raw_val) * (double)sensitivity * SENSOR_G_DOUBLE / 1000;
480 val->val1 = (int32_t)dval;
481 val->val2 = (((int32_t)(dval * 1000)) % 1000) * 1000;
482
483 }
484
lsm6dsl_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data,float sensitivity)485 static inline int lsm6dsl_accel_get_channel(enum sensor_channel chan,
486 struct sensor_value *val,
487 struct lsm6dsl_data *data,
488 float sensitivity)
489 {
490 switch (chan) {
491 case SENSOR_CHAN_ACCEL_X:
492 lsm6dsl_accel_convert(val, data->accel_sample_x, sensitivity);
493 break;
494 case SENSOR_CHAN_ACCEL_Y:
495 lsm6dsl_accel_convert(val, data->accel_sample_y, sensitivity);
496 break;
497 case SENSOR_CHAN_ACCEL_Z:
498 lsm6dsl_accel_convert(val, data->accel_sample_z, sensitivity);
499 break;
500 case SENSOR_CHAN_ACCEL_XYZ:
501 lsm6dsl_accel_convert(val, data->accel_sample_x, sensitivity);
502 lsm6dsl_accel_convert(val + 1, data->accel_sample_y,
503 sensitivity);
504 lsm6dsl_accel_convert(val + 2, data->accel_sample_z,
505 sensitivity);
506 break;
507 default:
508 return -ENOTSUP;
509 }
510
511 return 0;
512 }
513
lsm6dsl_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)514 static int lsm6dsl_accel_channel_get(enum sensor_channel chan,
515 struct sensor_value *val,
516 struct lsm6dsl_data *data)
517 {
518 return lsm6dsl_accel_get_channel(chan, val, data,
519 data->accel_sensitivity);
520 }
521
lsm6dsl_gyro_convert(struct sensor_value * val,int raw_val,float sensitivity)522 static inline void lsm6dsl_gyro_convert(struct sensor_value *val, int raw_val,
523 float sensitivity)
524 {
525 double dval;
526
527 /* Sensitivity is exposed in mdps/LSB */
528 /* Convert to rad/s */
529 dval = (double)(raw_val * (double)sensitivity * SENSOR_DEG2RAD_DOUBLE / 1000);
530 val->val1 = (int32_t)dval;
531 val->val2 = (((int32_t)(dval * 1000)) % 1000) * 1000;
532 }
533
lsm6dsl_gyro_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data,float sensitivity)534 static inline int lsm6dsl_gyro_get_channel(enum sensor_channel chan,
535 struct sensor_value *val,
536 struct lsm6dsl_data *data,
537 float sensitivity)
538 {
539 switch (chan) {
540 case SENSOR_CHAN_GYRO_X:
541 lsm6dsl_gyro_convert(val, data->gyro_sample_x, sensitivity);
542 break;
543 case SENSOR_CHAN_GYRO_Y:
544 lsm6dsl_gyro_convert(val, data->gyro_sample_y, sensitivity);
545 break;
546 case SENSOR_CHAN_GYRO_Z:
547 lsm6dsl_gyro_convert(val, data->gyro_sample_z, sensitivity);
548 break;
549 case SENSOR_CHAN_GYRO_XYZ:
550 lsm6dsl_gyro_convert(val, data->gyro_sample_x, sensitivity);
551 lsm6dsl_gyro_convert(val + 1, data->gyro_sample_y, sensitivity);
552 lsm6dsl_gyro_convert(val + 2, data->gyro_sample_z, sensitivity);
553 break;
554 default:
555 return -ENOTSUP;
556 }
557
558 return 0;
559 }
560
lsm6dsl_gyro_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)561 static int lsm6dsl_gyro_channel_get(enum sensor_channel chan,
562 struct sensor_value *val,
563 struct lsm6dsl_data *data)
564 {
565 return lsm6dsl_gyro_get_channel(chan, val, data,
566 data->gyro_sensitivity);
567 }
568
569 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
lsm6dsl_gyro_channel_get_temp(struct sensor_value * val,struct lsm6dsl_data * data)570 static void lsm6dsl_gyro_channel_get_temp(struct sensor_value *val,
571 struct lsm6dsl_data *data)
572 {
573 /* val = temp_sample / 256 + 25 */
574 val->val1 = data->temp_sample / 256 + 25;
575 val->val2 = (data->temp_sample % 256) * (1000000 / 256);
576 }
577 #endif
578
579 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
lsm6dsl_magn_convert(struct sensor_value * val,int raw_val,float sensitivity)580 static inline void lsm6dsl_magn_convert(struct sensor_value *val, int raw_val,
581 float sensitivity)
582 {
583 double dval;
584
585 /* Sensitivity is exposed in mgauss/LSB */
586 dval = (double)(raw_val * sensitivity);
587 val->val1 = (int32_t)dval / 1000000;
588 val->val2 = (int32_t)dval % 1000000;
589 }
590
lsm6dsl_magn_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)591 static inline int lsm6dsl_magn_get_channel(enum sensor_channel chan,
592 struct sensor_value *val,
593 struct lsm6dsl_data *data)
594 {
595 switch (chan) {
596 case SENSOR_CHAN_MAGN_X:
597 lsm6dsl_magn_convert(val,
598 data->magn_sample_x,
599 data->magn_sensitivity);
600 break;
601 case SENSOR_CHAN_MAGN_Y:
602 lsm6dsl_magn_convert(val,
603 data->magn_sample_y,
604 data->magn_sensitivity);
605 break;
606 case SENSOR_CHAN_MAGN_Z:
607 lsm6dsl_magn_convert(val,
608 data->magn_sample_z,
609 data->magn_sensitivity);
610 break;
611 case SENSOR_CHAN_MAGN_XYZ:
612 lsm6dsl_magn_convert(val,
613 data->magn_sample_x,
614 data->magn_sensitivity);
615 lsm6dsl_magn_convert(val + 1,
616 data->magn_sample_y,
617 data->magn_sensitivity);
618 lsm6dsl_magn_convert(val + 2,
619 data->magn_sample_z,
620 data->magn_sensitivity);
621 break;
622 default:
623 return -ENOTSUP;
624 }
625
626 return 0;
627 }
628
lsm6dsl_magn_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)629 static int lsm6dsl_magn_channel_get(enum sensor_channel chan,
630 struct sensor_value *val,
631 struct lsm6dsl_data *data)
632 {
633 return lsm6dsl_magn_get_channel(chan, val, data);
634 }
635 #endif
636
637 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
lps22hb_press_convert(struct sensor_value * val,int32_t raw_val)638 static inline void lps22hb_press_convert(struct sensor_value *val,
639 int32_t raw_val)
640 {
641 /* Pressure sensitivity is 4096 LSB/hPa */
642 /* Convert raw_val to val in kPa */
643 val->val1 = (raw_val >> 12) / 10;
644 val->val2 = (raw_val >> 12) % 10 * 100000 +
645 (((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
646 }
647
lps22hb_temp_convert(struct sensor_value * val,int16_t raw_val)648 static inline void lps22hb_temp_convert(struct sensor_value *val,
649 int16_t raw_val)
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
lsm6dsl_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)657 static int lsm6dsl_channel_get(const struct device *dev,
658 enum sensor_channel chan,
659 struct sensor_value *val)
660 {
661 struct lsm6dsl_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 lsm6dsl_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 lsm6dsl_gyro_channel_get(chan, val, data);
675 break;
676 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
677 case SENSOR_CHAN_DIE_TEMP:
678 lsm6dsl_gyro_channel_get_temp(val, data);
679 break;
680 #endif
681 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
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 lsm6dsl_magn_channel_get(chan, val, data);
687 break;
688 #endif
689 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
690 case SENSOR_CHAN_PRESS:
691 lps22hb_press_convert(val, data->sample_press);
692 break;
693
694 case SENSOR_CHAN_AMBIENT_TEMP:
695 lps22hb_temp_convert(val, data->sample_temp);
696 break;
697 #endif
698 default:
699 return -ENOTSUP;
700 }
701
702 return 0;
703 }
704
705 static const struct sensor_driver_api lsm6dsl_driver_api = {
706 .attr_set = lsm6dsl_attr_set,
707 #if CONFIG_LSM6DSL_TRIGGER
708 .trigger_set = lsm6dsl_trigger_set,
709 #endif
710 .sample_fetch = lsm6dsl_sample_fetch,
711 .channel_get = lsm6dsl_channel_get,
712 };
713
lsm6dsl_init_chip(const struct device * dev)714 static int lsm6dsl_init_chip(const struct device *dev)
715 {
716 struct lsm6dsl_data *data = dev->data;
717 uint8_t chip_id;
718
719 if (lsm6dsl_reboot(dev) < 0) {
720 LOG_DBG("failed to reboot device");
721 return -EIO;
722 }
723
724 if (data->hw_tf->read_reg(dev, LSM6DSL_REG_WHO_AM_I, &chip_id) < 0) {
725 LOG_DBG("failed reading chip id");
726 return -EIO;
727 }
728 if (chip_id != LSM6DSL_VAL_WHO_AM_I) {
729 LOG_DBG("invalid chip id 0x%x", chip_id);
730 return -EIO;
731 }
732
733 LOG_DBG("chip id 0x%x", chip_id);
734
735 if (lsm6dsl_accel_set_fs_raw(dev,
736 LSM6DSL_DEFAULT_ACCEL_FULLSCALE) < 0) {
737 LOG_DBG("failed to set accelerometer full-scale");
738 return -EIO;
739 }
740 data->accel_sensitivity = LSM6DSL_DEFAULT_ACCEL_SENSITIVITY;
741
742 if (lsm6dsl_accel_set_odr_raw(dev, CONFIG_LSM6DSL_ACCEL_ODR) < 0) {
743 LOG_DBG("failed to set accelerometer sampling rate");
744 return -EIO;
745 }
746
747 if (lsm6dsl_gyro_set_fs_raw(dev, LSM6DSL_DEFAULT_GYRO_FULLSCALE) < 0) {
748 LOG_DBG("failed to set gyroscope full-scale");
749 return -EIO;
750 }
751 data->gyro_sensitivity = LSM6DSL_DEFAULT_GYRO_SENSITIVITY;
752
753 if (lsm6dsl_gyro_set_odr_raw(dev, CONFIG_LSM6DSL_GYRO_ODR) < 0) {
754 LOG_DBG("failed to set gyroscope sampling rate");
755 return -EIO;
756 }
757
758 if (data->hw_tf->update_reg(dev,
759 LSM6DSL_REG_FIFO_CTRL5,
760 LSM6DSL_MASK_FIFO_CTRL5_FIFO_MODE,
761 0 << LSM6DSL_SHIFT_FIFO_CTRL5_FIFO_MODE) < 0) {
762 LOG_DBG("failed to set FIFO mode");
763 return -EIO;
764 }
765
766 if (data->hw_tf->update_reg(dev,
767 LSM6DSL_REG_CTRL3_C,
768 LSM6DSL_MASK_CTRL3_C_BDU |
769 LSM6DSL_MASK_CTRL3_C_BLE |
770 LSM6DSL_MASK_CTRL3_C_IF_INC,
771 (1 << LSM6DSL_SHIFT_CTRL3_C_BDU) |
772 (0 << LSM6DSL_SHIFT_CTRL3_C_BLE) |
773 (1 << LSM6DSL_SHIFT_CTRL3_C_IF_INC)) < 0) {
774 LOG_DBG("failed to set BDU, BLE and burst");
775 return -EIO;
776 }
777
778 if (data->hw_tf->update_reg(dev,
779 LSM6DSL_REG_CTRL6_C,
780 LSM6DSL_MASK_CTRL6_C_XL_HM_MODE,
781 (1 << LSM6DSL_SHIFT_CTRL6_C_XL_HM_MODE)) < 0) {
782 LOG_DBG("failed to disable accelerometer high performance mode");
783 return -EIO;
784 }
785
786 if (data->hw_tf->update_reg(dev,
787 LSM6DSL_REG_CTRL7_G,
788 LSM6DSL_MASK_CTRL7_G_HM_MODE,
789 (1 << LSM6DSL_SHIFT_CTRL7_G_HM_MODE)) < 0) {
790 LOG_DBG("failed to disable gyroscope high performance mode");
791 return -EIO;
792 }
793
794 return 0;
795 }
796
lsm6dsl_init(const struct device * dev)797 static int lsm6dsl_init(const struct device *dev)
798 {
799 int ret;
800 const struct lsm6dsl_config * const config = dev->config;
801
802 ret = config->bus_init(dev);
803 if (ret < 0) {
804 LOG_ERR("Failed to initialize sensor bus");
805 return ret;
806 }
807
808 ret = lsm6dsl_init_chip(dev);
809 if (ret < 0) {
810 LOG_ERR("Failed to initialize chip");
811 return ret;
812 }
813
814 #ifdef CONFIG_LSM6DSL_TRIGGER
815 ret = lsm6dsl_init_interrupt(dev);
816 if (ret < 0) {
817 LOG_ERR("Failed to initialize interrupt.");
818 return ret;
819 }
820 #endif
821
822 #ifdef CONFIG_LSM6DSL_SENSORHUB
823 ret = lsm6dsl_shub_init_external_chip(dev);
824 if (ret < 0) {
825 LOG_ERR("Failed to initialize external chip");
826 return ret;
827 }
828 #endif
829
830 return 0;
831 }
832
833 #ifdef CONFIG_PM_DEVICE
lsm6dsl_pm_action(const struct device * dev,enum pm_device_action action)834 static int lsm6dsl_pm_action(const struct device *dev,
835 enum pm_device_action action)
836 {
837 struct lsm6dsl_data *data = dev->data;
838 int ret = -EIO;
839 uint8_t accel_odr = 0;
840 uint8_t gyro_odr = 0;
841
842 switch (action) {
843 case PM_DEVICE_ACTION_RESUME:
844 /* Restore saved ODR values */
845 accel_odr = lsm6dsl_freq_to_odr_val(data->accel_freq);
846 ret = lsm6dsl_accel_set_odr_raw(dev, accel_odr);
847 if (ret < 0) {
848 LOG_ERR("Failed to resume accelerometer");
849 break;
850 }
851 gyro_odr = lsm6dsl_freq_to_odr_val(data->gyro_freq);
852 ret = lsm6dsl_gyro_set_odr_raw(dev, gyro_odr);
853 if (ret < 0) {
854 LOG_ERR("Failed to resume gyro");
855 break;
856 }
857 break;
858 case PM_DEVICE_ACTION_SUSPEND:
859 /*
860 * Set accelerometer ODR to power-down. Don't use the direct
861 * function to not overwrite the saved value
862 */
863 ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL1_XL,
864 LSM6DSL_MASK_CTRL1_XL_ODR_XL, 0);
865 if (ret < 0) {
866 LOG_ERR("Failed to suspend accelerometer");
867 break;
868 }
869 /* Set gyro ODR to power-down */
870 ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL2_G,
871 LSM6DSL_MASK_CTRL2_G_ODR_G, 0);
872 if (ret < 0) {
873 LOG_ERR("Failed to suspend gyro");
874 break;
875 }
876
877 break;
878 default:
879 return -ENOTSUP;
880 }
881
882 return ret;
883 }
884 #endif
885
886
887 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
888 #warning "LSM6DSL driver enabled without any devices"
889 #endif
890
891 /*
892 * Device creation macro, shared by LSM6DSL_DEFINE_SPI() and
893 * LSM6DSL_DEFINE_I2C().
894 */
895
896 #define LSM6DSL_DEVICE_INIT(inst) \
897 PM_DEVICE_DT_INST_DEFINE(inst, lsm6dsl_pm_action); \
898 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
899 lsm6dsl_init, \
900 PM_DEVICE_DT_INST_GET(inst), \
901 &lsm6dsl_data_##inst, \
902 &lsm6dsl_config_##inst, \
903 POST_KERNEL, \
904 CONFIG_SENSOR_INIT_PRIORITY, \
905 &lsm6dsl_driver_api);
906
907 /*
908 * Instantiation macros used when a device is on a SPI bus.
909 */
910
911 #ifdef CONFIG_LSM6DSL_TRIGGER
912 #define LSM6DSL_CFG_IRQ(inst) \
913 .int_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios),
914 #else
915 #define LSM6DSL_CFG_IRQ(inst)
916 #endif /* CONFIG_LSM6DSL_TRIGGER */
917
918 #define LSM6DSL_CONFIG_SPI(inst) \
919 { \
920 .bus_init = lsm6dsl_spi_init, \
921 .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \
922 SPI_OP_MODE_MASTER | \
923 SPI_MODE_CPOL | \
924 SPI_MODE_CPHA, 0), \
925 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
926 (LSM6DSL_CFG_IRQ(inst)), ()) \
927 }
928
929 #define LSM6DSL_DEFINE_SPI(inst) \
930 static struct lsm6dsl_data lsm6dsl_data_##inst; \
931 static const struct lsm6dsl_config lsm6dsl_config_##inst = \
932 LSM6DSL_CONFIG_SPI(inst); \
933 LSM6DSL_DEVICE_INIT(inst)
934
935 /*
936 * Instantiation macros used when a device is on an I2C bus.
937 */
938
939 #define LSM6DSL_CONFIG_I2C(inst) \
940 { \
941 .bus_init = lsm6dsl_i2c_init, \
942 .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
943 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
944 (LSM6DSL_CFG_IRQ(inst)), ()) \
945 }
946
947 #define LSM6DSL_DEFINE_I2C(inst) \
948 static struct lsm6dsl_data lsm6dsl_data_##inst; \
949 static const struct lsm6dsl_config lsm6dsl_config_##inst = \
950 LSM6DSL_CONFIG_I2C(inst); \
951 LSM6DSL_DEVICE_INIT(inst)
952 /*
953 * Main instantiation macro. Use of COND_CODE_1() selects the right
954 * bus-specific macro at preprocessor time.
955 */
956
957 #define LSM6DSL_DEFINE(inst) \
958 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
959 (LSM6DSL_DEFINE_SPI(inst)), \
960 (LSM6DSL_DEFINE_I2C(inst)))
961
962 DT_INST_FOREACH_STATUS_OKAY(LSM6DSL_DEFINE)
963