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 int64_t dval;
476
477 /* Sensitivity is exposed in ug/LSB */
478 /* Convert to m/s^2 */
479 dval = (int64_t)raw_val * sensitivity;
480 sensor_ug_to_ms2(dval, val);
481 }
482
lsm6dsl_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data,float sensitivity)483 static inline int lsm6dsl_accel_get_channel(enum sensor_channel chan,
484 struct sensor_value *val,
485 struct lsm6dsl_data *data,
486 float sensitivity)
487 {
488 switch (chan) {
489 case SENSOR_CHAN_ACCEL_X:
490 lsm6dsl_accel_convert(val, data->accel_sample_x, sensitivity);
491 break;
492 case SENSOR_CHAN_ACCEL_Y:
493 lsm6dsl_accel_convert(val, data->accel_sample_y, sensitivity);
494 break;
495 case SENSOR_CHAN_ACCEL_Z:
496 lsm6dsl_accel_convert(val, data->accel_sample_z, sensitivity);
497 break;
498 case SENSOR_CHAN_ACCEL_XYZ:
499 lsm6dsl_accel_convert(val, data->accel_sample_x, sensitivity);
500 lsm6dsl_accel_convert(val + 1, data->accel_sample_y,
501 sensitivity);
502 lsm6dsl_accel_convert(val + 2, data->accel_sample_z,
503 sensitivity);
504 break;
505 default:
506 return -ENOTSUP;
507 }
508
509 return 0;
510 }
511
lsm6dsl_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)512 static int lsm6dsl_accel_channel_get(enum sensor_channel chan,
513 struct sensor_value *val,
514 struct lsm6dsl_data *data)
515 {
516 return lsm6dsl_accel_get_channel(chan, val, data,
517 data->accel_sensitivity);
518 }
519
lsm6dsl_gyro_convert(struct sensor_value * val,int raw_val,float sensitivity)520 static inline void lsm6dsl_gyro_convert(struct sensor_value *val, int raw_val,
521 float sensitivity)
522 {
523 int64_t dval;
524
525 /* Sensitivity is exposed in udps/LSB */
526 /* So, calculate value in 10 udps unit and then to rad/s */
527 dval = (int64_t)raw_val * sensitivity / 10;
528 sensor_10udegrees_to_rad(dval, val);
529 }
530
lsm6dsl_gyro_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data,float sensitivity)531 static inline int lsm6dsl_gyro_get_channel(enum sensor_channel chan,
532 struct sensor_value *val,
533 struct lsm6dsl_data *data,
534 float sensitivity)
535 {
536 switch (chan) {
537 case SENSOR_CHAN_GYRO_X:
538 lsm6dsl_gyro_convert(val, data->gyro_sample_x, sensitivity);
539 break;
540 case SENSOR_CHAN_GYRO_Y:
541 lsm6dsl_gyro_convert(val, data->gyro_sample_y, sensitivity);
542 break;
543 case SENSOR_CHAN_GYRO_Z:
544 lsm6dsl_gyro_convert(val, data->gyro_sample_z, sensitivity);
545 break;
546 case SENSOR_CHAN_GYRO_XYZ:
547 lsm6dsl_gyro_convert(val, data->gyro_sample_x, sensitivity);
548 lsm6dsl_gyro_convert(val + 1, data->gyro_sample_y, sensitivity);
549 lsm6dsl_gyro_convert(val + 2, data->gyro_sample_z, sensitivity);
550 break;
551 default:
552 return -ENOTSUP;
553 }
554
555 return 0;
556 }
557
lsm6dsl_gyro_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)558 static int lsm6dsl_gyro_channel_get(enum sensor_channel chan,
559 struct sensor_value *val,
560 struct lsm6dsl_data *data)
561 {
562 return lsm6dsl_gyro_get_channel(chan, val, data,
563 data->gyro_sensitivity);
564 }
565
566 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
lsm6dsl_gyro_channel_get_temp(struct sensor_value * val,struct lsm6dsl_data * data)567 static void lsm6dsl_gyro_channel_get_temp(struct sensor_value *val,
568 struct lsm6dsl_data *data)
569 {
570 /* val = temp_sample / 256 + 25 */
571 val->val1 = data->temp_sample / 256 + 25;
572 val->val2 = (data->temp_sample % 256) * (1000000 / 256);
573 }
574 #endif
575
576 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
lsm6dsl_magn_convert(struct sensor_value * val,int raw_val,float sensitivity)577 static inline void lsm6dsl_magn_convert(struct sensor_value *val, int raw_val,
578 float sensitivity)
579 {
580 double dval;
581
582 /* Sensitivity is exposed in mgauss/LSB */
583 dval = (double)(raw_val * sensitivity);
584 val->val1 = (int32_t)dval / 1000000;
585 val->val2 = (int32_t)dval % 1000000;
586 }
587
lsm6dsl_magn_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)588 static inline int lsm6dsl_magn_get_channel(enum sensor_channel chan,
589 struct sensor_value *val,
590 struct lsm6dsl_data *data)
591 {
592 switch (chan) {
593 case SENSOR_CHAN_MAGN_X:
594 lsm6dsl_magn_convert(val,
595 data->magn_sample_x,
596 data->magn_sensitivity);
597 break;
598 case SENSOR_CHAN_MAGN_Y:
599 lsm6dsl_magn_convert(val,
600 data->magn_sample_y,
601 data->magn_sensitivity);
602 break;
603 case SENSOR_CHAN_MAGN_Z:
604 lsm6dsl_magn_convert(val,
605 data->magn_sample_z,
606 data->magn_sensitivity);
607 break;
608 case SENSOR_CHAN_MAGN_XYZ:
609 lsm6dsl_magn_convert(val,
610 data->magn_sample_x,
611 data->magn_sensitivity);
612 lsm6dsl_magn_convert(val + 1,
613 data->magn_sample_y,
614 data->magn_sensitivity);
615 lsm6dsl_magn_convert(val + 2,
616 data->magn_sample_z,
617 data->magn_sensitivity);
618 break;
619 default:
620 return -ENOTSUP;
621 }
622
623 return 0;
624 }
625
lsm6dsl_magn_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6dsl_data * data)626 static int lsm6dsl_magn_channel_get(enum sensor_channel chan,
627 struct sensor_value *val,
628 struct lsm6dsl_data *data)
629 {
630 return lsm6dsl_magn_get_channel(chan, val, data);
631 }
632 #endif
633
634 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
lps22hb_press_convert(struct sensor_value * val,int32_t raw_val)635 static inline void lps22hb_press_convert(struct sensor_value *val,
636 int32_t raw_val)
637 {
638 /* Pressure sensitivity is 4096 LSB/hPa */
639 /* Convert raw_val to val in kPa */
640 val->val1 = (raw_val >> 12) / 10;
641 val->val2 = (raw_val >> 12) % 10 * 100000 +
642 (((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
643 }
644
lps22hb_temp_convert(struct sensor_value * val,int16_t raw_val)645 static inline void lps22hb_temp_convert(struct sensor_value *val,
646 int16_t raw_val)
647 {
648 /* Temperature sensitivity is 100 LSB/deg C */
649 val->val1 = raw_val / 100;
650 val->val2 = (int32_t)raw_val % 100 * (10000);
651 }
652 #endif
653
lsm6dsl_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)654 static int lsm6dsl_channel_get(const struct device *dev,
655 enum sensor_channel chan,
656 struct sensor_value *val)
657 {
658 struct lsm6dsl_data *data = dev->data;
659
660 switch (chan) {
661 case SENSOR_CHAN_ACCEL_X:
662 case SENSOR_CHAN_ACCEL_Y:
663 case SENSOR_CHAN_ACCEL_Z:
664 case SENSOR_CHAN_ACCEL_XYZ:
665 lsm6dsl_accel_channel_get(chan, val, data);
666 break;
667 case SENSOR_CHAN_GYRO_X:
668 case SENSOR_CHAN_GYRO_Y:
669 case SENSOR_CHAN_GYRO_Z:
670 case SENSOR_CHAN_GYRO_XYZ:
671 lsm6dsl_gyro_channel_get(chan, val, data);
672 break;
673 #if defined(CONFIG_LSM6DSL_ENABLE_TEMP)
674 case SENSOR_CHAN_DIE_TEMP:
675 lsm6dsl_gyro_channel_get_temp(val, data);
676 break;
677 #endif
678 #if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL) || defined(CONFIG_LSM6DSL_EXT0_LIS3MDL)
679 case SENSOR_CHAN_MAGN_X:
680 case SENSOR_CHAN_MAGN_Y:
681 case SENSOR_CHAN_MAGN_Z:
682 case SENSOR_CHAN_MAGN_XYZ:
683 lsm6dsl_magn_channel_get(chan, val, data);
684 break;
685 #endif
686 #if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
687 case SENSOR_CHAN_PRESS:
688 lps22hb_press_convert(val, data->sample_press);
689 break;
690
691 case SENSOR_CHAN_AMBIENT_TEMP:
692 lps22hb_temp_convert(val, data->sample_temp);
693 break;
694 #endif
695 default:
696 return -ENOTSUP;
697 }
698
699 return 0;
700 }
701
702 static const struct sensor_driver_api lsm6dsl_driver_api = {
703 .attr_set = lsm6dsl_attr_set,
704 #if CONFIG_LSM6DSL_TRIGGER
705 .trigger_set = lsm6dsl_trigger_set,
706 #endif
707 .sample_fetch = lsm6dsl_sample_fetch,
708 .channel_get = lsm6dsl_channel_get,
709 };
710
lsm6dsl_init_chip(const struct device * dev)711 static int lsm6dsl_init_chip(const struct device *dev)
712 {
713 struct lsm6dsl_data *data = dev->data;
714 uint8_t chip_id;
715
716 if (lsm6dsl_reboot(dev) < 0) {
717 LOG_DBG("failed to reboot device");
718 return -EIO;
719 }
720
721 if (data->hw_tf->read_reg(dev, LSM6DSL_REG_WHO_AM_I, &chip_id) < 0) {
722 LOG_DBG("failed reading chip id");
723 return -EIO;
724 }
725 if (chip_id != LSM6DSL_VAL_WHO_AM_I) {
726 LOG_DBG("invalid chip id 0x%x", chip_id);
727 return -EIO;
728 }
729
730 LOG_DBG("chip id 0x%x", chip_id);
731
732 if (lsm6dsl_accel_set_fs_raw(dev,
733 LSM6DSL_DEFAULT_ACCEL_FULLSCALE) < 0) {
734 LOG_DBG("failed to set accelerometer full-scale");
735 return -EIO;
736 }
737 data->accel_sensitivity = LSM6DSL_DEFAULT_ACCEL_SENSITIVITY;
738
739 if (lsm6dsl_accel_set_odr_raw(dev, CONFIG_LSM6DSL_ACCEL_ODR) < 0) {
740 LOG_DBG("failed to set accelerometer sampling rate");
741 return -EIO;
742 }
743
744 if (lsm6dsl_gyro_set_fs_raw(dev, LSM6DSL_DEFAULT_GYRO_FULLSCALE) < 0) {
745 LOG_DBG("failed to set gyroscope full-scale");
746 return -EIO;
747 }
748 data->gyro_sensitivity = LSM6DSL_DEFAULT_GYRO_SENSITIVITY;
749
750 if (lsm6dsl_gyro_set_odr_raw(dev, CONFIG_LSM6DSL_GYRO_ODR) < 0) {
751 LOG_DBG("failed to set gyroscope sampling rate");
752 return -EIO;
753 }
754
755 if (data->hw_tf->update_reg(dev,
756 LSM6DSL_REG_FIFO_CTRL5,
757 LSM6DSL_MASK_FIFO_CTRL5_FIFO_MODE,
758 0 << LSM6DSL_SHIFT_FIFO_CTRL5_FIFO_MODE) < 0) {
759 LOG_DBG("failed to set FIFO mode");
760 return -EIO;
761 }
762
763 if (data->hw_tf->update_reg(dev,
764 LSM6DSL_REG_CTRL3_C,
765 LSM6DSL_MASK_CTRL3_C_BDU |
766 LSM6DSL_MASK_CTRL3_C_BLE |
767 LSM6DSL_MASK_CTRL3_C_IF_INC,
768 (1 << LSM6DSL_SHIFT_CTRL3_C_BDU) |
769 (0 << LSM6DSL_SHIFT_CTRL3_C_BLE) |
770 (1 << LSM6DSL_SHIFT_CTRL3_C_IF_INC)) < 0) {
771 LOG_DBG("failed to set BDU, BLE and burst");
772 return -EIO;
773 }
774
775 if (data->hw_tf->update_reg(dev,
776 LSM6DSL_REG_CTRL6_C,
777 LSM6DSL_MASK_CTRL6_C_XL_HM_MODE,
778 (1 << LSM6DSL_SHIFT_CTRL6_C_XL_HM_MODE)) < 0) {
779 LOG_DBG("failed to disable accelerometer high performance mode");
780 return -EIO;
781 }
782
783 if (data->hw_tf->update_reg(dev,
784 LSM6DSL_REG_CTRL7_G,
785 LSM6DSL_MASK_CTRL7_G_HM_MODE,
786 (1 << LSM6DSL_SHIFT_CTRL7_G_HM_MODE)) < 0) {
787 LOG_DBG("failed to disable gyroscope high performance mode");
788 return -EIO;
789 }
790
791 return 0;
792 }
793
lsm6dsl_init(const struct device * dev)794 static int lsm6dsl_init(const struct device *dev)
795 {
796 int ret;
797 const struct lsm6dsl_config * const config = dev->config;
798
799 ret = config->bus_init(dev);
800 if (ret < 0) {
801 LOG_ERR("Failed to initialize sensor bus");
802 return ret;
803 }
804
805 ret = lsm6dsl_init_chip(dev);
806 if (ret < 0) {
807 LOG_ERR("Failed to initialize chip");
808 return ret;
809 }
810
811 #ifdef CONFIG_LSM6DSL_TRIGGER
812 ret = lsm6dsl_init_interrupt(dev);
813 if (ret < 0) {
814 LOG_ERR("Failed to initialize interrupt.");
815 return ret;
816 }
817 #endif
818
819 #ifdef CONFIG_LSM6DSL_SENSORHUB
820 ret = lsm6dsl_shub_init_external_chip(dev);
821 if (ret < 0) {
822 LOG_ERR("Failed to initialize external chip");
823 return ret;
824 }
825 #endif
826
827 return 0;
828 }
829
830 #ifdef CONFIG_PM_DEVICE
lsm6dsl_pm_action(const struct device * dev,enum pm_device_action action)831 static int lsm6dsl_pm_action(const struct device *dev,
832 enum pm_device_action action)
833 {
834 struct lsm6dsl_data *data = dev->data;
835 int ret = -EIO;
836 uint8_t accel_odr = 0;
837 uint8_t gyro_odr = 0;
838
839 switch (action) {
840 case PM_DEVICE_ACTION_RESUME:
841 /* Restore saved ODR values */
842 accel_odr = lsm6dsl_freq_to_odr_val(data->accel_freq);
843 ret = lsm6dsl_accel_set_odr_raw(dev, accel_odr);
844 if (ret < 0) {
845 LOG_ERR("Failed to resume accelerometer");
846 break;
847 }
848 gyro_odr = lsm6dsl_freq_to_odr_val(data->gyro_freq);
849 ret = lsm6dsl_gyro_set_odr_raw(dev, gyro_odr);
850 if (ret < 0) {
851 LOG_ERR("Failed to resume gyro");
852 break;
853 }
854 break;
855 case PM_DEVICE_ACTION_SUSPEND:
856 /*
857 * Set accelerometer ODR to power-down. Don't use the direct
858 * function to not overwrite the saved value
859 */
860 ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL1_XL,
861 LSM6DSL_MASK_CTRL1_XL_ODR_XL, 0);
862 if (ret < 0) {
863 LOG_ERR("Failed to suspend accelerometer");
864 break;
865 }
866 /* Set gyro ODR to power-down */
867 ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL2_G,
868 LSM6DSL_MASK_CTRL2_G_ODR_G, 0);
869 if (ret < 0) {
870 LOG_ERR("Failed to suspend gyro");
871 break;
872 }
873
874 break;
875 default:
876 return -ENOTSUP;
877 }
878
879 return ret;
880 }
881 #endif
882
883
884 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
885 #warning "LSM6DSL driver enabled without any devices"
886 #endif
887
888 /*
889 * Device creation macro, shared by LSM6DSL_DEFINE_SPI() and
890 * LSM6DSL_DEFINE_I2C().
891 */
892
893 #define LSM6DSL_DEVICE_INIT(inst) \
894 PM_DEVICE_DT_INST_DEFINE(inst, lsm6dsl_pm_action); \
895 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
896 lsm6dsl_init, \
897 PM_DEVICE_DT_INST_GET(inst), \
898 &lsm6dsl_data_##inst, \
899 &lsm6dsl_config_##inst, \
900 POST_KERNEL, \
901 CONFIG_SENSOR_INIT_PRIORITY, \
902 &lsm6dsl_driver_api);
903
904 /*
905 * Instantiation macros used when a device is on a SPI bus.
906 */
907
908 #ifdef CONFIG_LSM6DSL_TRIGGER
909 #define LSM6DSL_CFG_IRQ(inst) \
910 .int_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios),
911 #else
912 #define LSM6DSL_CFG_IRQ(inst)
913 #endif /* CONFIG_LSM6DSL_TRIGGER */
914
915 #define LSM6DSL_CONFIG_SPI(inst) \
916 { \
917 .bus_init = lsm6dsl_spi_init, \
918 .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \
919 SPI_OP_MODE_MASTER | \
920 SPI_MODE_CPOL | \
921 SPI_MODE_CPHA, 0), \
922 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
923 (LSM6DSL_CFG_IRQ(inst)), ()) \
924 }
925
926 #define LSM6DSL_DEFINE_SPI(inst) \
927 static struct lsm6dsl_data lsm6dsl_data_##inst; \
928 static const struct lsm6dsl_config lsm6dsl_config_##inst = \
929 LSM6DSL_CONFIG_SPI(inst); \
930 LSM6DSL_DEVICE_INIT(inst)
931
932 /*
933 * Instantiation macros used when a device is on an I2C bus.
934 */
935
936 #define LSM6DSL_CONFIG_I2C(inst) \
937 { \
938 .bus_init = lsm6dsl_i2c_init, \
939 .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
940 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
941 (LSM6DSL_CFG_IRQ(inst)), ()) \
942 }
943
944 #define LSM6DSL_DEFINE_I2C(inst) \
945 static struct lsm6dsl_data lsm6dsl_data_##inst; \
946 static const struct lsm6dsl_config lsm6dsl_config_##inst = \
947 LSM6DSL_CONFIG_I2C(inst); \
948 LSM6DSL_DEVICE_INIT(inst)
949 /*
950 * Main instantiation macro. Use of COND_CODE_1() selects the right
951 * bus-specific macro at preprocessor time.
952 */
953
954 #define LSM6DSL_DEFINE(inst) \
955 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
956 (LSM6DSL_DEFINE_SPI(inst)), \
957 (LSM6DSL_DEFINE_I2C(inst)))
958
959 DT_INST_FOREACH_STATUS_OKAY(LSM6DSL_DEFINE)
960