1 /* lsm6ds0.c - Driver for LSM6DS0 accelerometer, gyroscope and
2 * temperature sensor
3 */
4
5 /*
6 * Copyright (c) 2016 Intel Corporation
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #define DT_DRV_COMPAT st_lsm6ds0
12
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/logging/log.h>
20
21 #include "lsm6ds0.h"
22
23 LOG_MODULE_REGISTER(LSM6DS0, CONFIG_SENSOR_LOG_LEVEL);
24
lsm6ds0_reboot(const struct device * dev)25 static inline int lsm6ds0_reboot(const struct device *dev)
26 {
27 const struct lsm6ds0_config *config = dev->config;
28
29 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG8,
30 LSM6DS0_MASK_CTRL_REG8_BOOT,
31 1 << LSM6DS0_SHIFT_CTRL_REG8_BOOT) < 0) {
32 return -EIO;
33 }
34
35 k_busy_wait(USEC_PER_MSEC * 50U);
36
37 return 0;
38 }
39
lsm6ds0_accel_axis_ctrl(const struct device * dev,int x_en,int y_en,int z_en)40 static inline int lsm6ds0_accel_axis_ctrl(const struct device *dev, int x_en,
41 int y_en, int z_en)
42 {
43 const struct lsm6ds0_config *config = dev->config;
44 uint8_t state = (x_en << LSM6DS0_SHIFT_CTRL_REG5_XL_XEN_XL) |
45 (y_en << LSM6DS0_SHIFT_CTRL_REG5_XL_YEN_XL) |
46 (z_en << LSM6DS0_SHIFT_CTRL_REG5_XL_ZEN_XL);
47
48 return i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG5_XL,
49 LSM6DS0_MASK_CTRL_REG5_XL_XEN_XL |
50 LSM6DS0_MASK_CTRL_REG5_XL_YEN_XL |
51 LSM6DS0_MASK_CTRL_REG5_XL_ZEN_XL,
52 state);
53 }
54
lsm6ds0_accel_set_fs_raw(const struct device * dev,uint8_t fs)55 static int lsm6ds0_accel_set_fs_raw(const struct device *dev, uint8_t fs)
56 {
57 const struct lsm6ds0_config *config = dev->config;
58
59 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG6_XL,
60 LSM6DS0_MASK_CTRL_REG6_XL_FS_XL,
61 fs << LSM6DS0_SHIFT_CTRL_REG6_XL_FS_XL) < 0) {
62 return -EIO;
63 }
64
65 return 0;
66 }
67
lsm6ds0_accel_set_odr_raw(const struct device * dev,uint8_t odr)68 static int lsm6ds0_accel_set_odr_raw(const struct device *dev, uint8_t odr)
69 {
70 const struct lsm6ds0_config *config = dev->config;
71
72 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG6_XL,
73 LSM6DS0_MASK_CTRL_REG6_XL_ODR_XL,
74 odr << LSM6DS0_SHIFT_CTRL_REG6_XL_ODR_XL) < 0) {
75 return -EIO;
76 }
77
78 return 0;
79 }
80
lsm6ds0_gyro_axis_ctrl(const struct device * dev,int x_en,int y_en,int z_en)81 static inline int lsm6ds0_gyro_axis_ctrl(const struct device *dev, int x_en,
82 int y_en,
83 int z_en)
84 {
85 const struct lsm6ds0_config *config = dev->config;
86 uint8_t state = (x_en << LSM6DS0_SHIFT_CTRL_REG4_XEN_G) |
87 (y_en << LSM6DS0_SHIFT_CTRL_REG4_YEN_G) |
88 (z_en << LSM6DS0_SHIFT_CTRL_REG4_ZEN_G);
89
90 return i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG4,
91 LSM6DS0_MASK_CTRL_REG4_XEN_G |
92 LSM6DS0_MASK_CTRL_REG4_YEN_G |
93 LSM6DS0_MASK_CTRL_REG4_ZEN_G,
94 state);
95 }
96
lsm6ds0_gyro_set_fs_raw(const struct device * dev,uint8_t fs)97 static int lsm6ds0_gyro_set_fs_raw(const struct device *dev, uint8_t fs)
98 {
99 const struct lsm6ds0_config *config = dev->config;
100
101 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG1_G,
102 LSM6DS0_MASK_CTRL_REG1_G_FS_G,
103 fs << LSM6DS0_SHIFT_CTRL_REG1_G_FS_G) < 0) {
104 return -EIO;
105 }
106
107 return 0;
108 }
109
lsm6ds0_gyro_set_odr_raw(const struct device * dev,uint8_t odr)110 static int lsm6ds0_gyro_set_odr_raw(const struct device *dev, uint8_t odr)
111 {
112 const struct lsm6ds0_config *config = dev->config;
113
114 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG1_G,
115 LSM6DS0_MASK_CTRL_REG1_G_ODR_G,
116 odr << LSM6DS0_SHIFT_CTRL_REG1_G_ODR_G) < 0) {
117 return -EIO;
118 }
119
120 return 0;
121 }
122
lsm6ds0_sample_fetch_accel(const struct device * dev)123 static int lsm6ds0_sample_fetch_accel(const struct device *dev)
124 {
125 struct lsm6ds0_data *data = dev->data;
126 const struct lsm6ds0_config *config = dev->config;
127 uint8_t buf[6];
128
129 if (i2c_burst_read_dt(&config->i2c, LSM6DS0_REG_OUT_X_L_XL, buf, sizeof(buf)) < 0) {
130 LOG_DBG("failed to read sample");
131 return -EIO;
132 }
133
134 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_X_AXIS)
135 data->accel_sample_x = (int16_t)((uint16_t)(buf[0]) |
136 ((uint16_t)(buf[1]) << 8));
137 #endif
138 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Y_AXIS)
139 data->accel_sample_y = (int16_t)((uint16_t)(buf[2]) |
140 ((uint16_t)(buf[3]) << 8));
141 #endif
142 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Z_AXIS)
143 data->accel_sample_z = (int16_t)((uint16_t)(buf[4]) |
144 ((uint16_t)(buf[5]) << 8));
145 #endif
146
147 return 0;
148 }
149
lsm6ds0_sample_fetch_gyro(const struct device * dev)150 static int lsm6ds0_sample_fetch_gyro(const struct device *dev)
151 {
152 struct lsm6ds0_data *data = dev->data;
153 const struct lsm6ds0_config *config = dev->config;
154 uint8_t buf[6];
155
156 if (i2c_burst_read_dt(&config->i2c, LSM6DS0_REG_OUT_X_L_G, buf, sizeof(buf)) < 0) {
157 LOG_DBG("failed to read sample");
158 return -EIO;
159 }
160
161 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_X_AXIS)
162 data->gyro_sample_x = (int16_t)((uint16_t)(buf[0]) |
163 ((uint16_t)(buf[1]) << 8));
164 #endif
165 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Y_AXIS)
166 data->gyro_sample_y = (int16_t)((uint16_t)(buf[2]) |
167 ((uint16_t)(buf[3]) << 8));
168 #endif
169 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Z_AXIS)
170 data->gyro_sample_z = (int16_t)((uint16_t)(buf[4]) |
171 ((uint16_t)(buf[5]) << 8));
172 #endif
173
174 return 0;
175 }
176
177 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
lsm6ds0_sample_fetch_temp(const struct device * dev)178 static int lsm6ds0_sample_fetch_temp(const struct device *dev)
179 {
180 struct lsm6ds0_data *data = dev->data;
181 const struct lsm6ds0_config *config = dev->config;
182 uint8_t buf[2];
183
184 if (i2c_burst_read_dt(&config->i2c, LSM6DS0_REG_OUT_TEMP_L, buf, sizeof(buf)) < 0) {
185 LOG_DBG("failed to read sample");
186 return -EIO;
187 }
188
189 data->temp_sample = (int16_t)((uint16_t)(buf[0]) |
190 ((uint16_t)(buf[1]) << 8));
191
192 return 0;
193 }
194 #endif
195
lsm6ds0_sample_fetch(const struct device * dev,enum sensor_channel chan)196 static int lsm6ds0_sample_fetch(const struct device *dev,
197 enum sensor_channel chan)
198 {
199 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
200 chan == SENSOR_CHAN_ACCEL_XYZ ||
201 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
202 chan == SENSOR_CHAN_DIE_TEMP ||
203 #endif
204 chan == SENSOR_CHAN_GYRO_XYZ);
205
206 switch (chan) {
207 case SENSOR_CHAN_ACCEL_XYZ:
208 lsm6ds0_sample_fetch_accel(dev);
209 break;
210 case SENSOR_CHAN_GYRO_XYZ:
211 lsm6ds0_sample_fetch_gyro(dev);
212 break;
213 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
214 case SENSOR_CHAN_DIE_TEMP:
215 lsm6ds0_sample_fetch_temp(dev);
216 break;
217 #endif
218 case SENSOR_CHAN_ALL:
219 lsm6ds0_sample_fetch_accel(dev);
220 lsm6ds0_sample_fetch_gyro(dev);
221 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
222 lsm6ds0_sample_fetch_temp(dev);
223 #endif
224 break;
225 default:
226 return -ENOTSUP;
227 }
228
229 return 0;
230 }
231
lsm6ds0_accel_convert(struct sensor_value * val,int raw_val,float scale)232 static inline void lsm6ds0_accel_convert(struct sensor_value *val, int raw_val,
233 float scale)
234 {
235 double dval;
236
237 dval = (double)(raw_val) * (double)scale / 32767.0;
238 val->val1 = (int32_t)dval;
239 val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
240 }
241
lsm6ds0_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6ds0_data * data,float scale)242 static inline int lsm6ds0_accel_get_channel(enum sensor_channel chan,
243 struct sensor_value *val,
244 struct lsm6ds0_data *data,
245 float scale)
246 {
247 switch (chan) {
248 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_X_AXIS)
249 case SENSOR_CHAN_ACCEL_X:
250 lsm6ds0_accel_convert(val, data->accel_sample_x, scale);
251 break;
252 #endif
253 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Y_AXIS)
254 case SENSOR_CHAN_ACCEL_Y:
255 lsm6ds0_accel_convert(val, data->accel_sample_y, scale);
256 break;
257 #endif
258 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Z_AXIS)
259 case SENSOR_CHAN_ACCEL_Z:
260 lsm6ds0_accel_convert(val, data->accel_sample_z, scale);
261 break;
262 #endif
263 case SENSOR_CHAN_ACCEL_XYZ:
264 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_X_AXIS)
265 lsm6ds0_accel_convert(val, data->accel_sample_x, scale);
266 #endif
267 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Y_AXIS)
268 lsm6ds0_accel_convert(val + 1, data->accel_sample_y, scale);
269 #endif
270 #if defined(CONFIG_LSM6DS0_ACCEL_ENABLE_Z_AXIS)
271 lsm6ds0_accel_convert(val + 2, data->accel_sample_z, scale);
272 #endif
273 break;
274 default:
275 return -ENOTSUP;
276 }
277
278 return 0;
279 }
280
lsm6ds0_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6ds0_data * data)281 static int lsm6ds0_accel_channel_get(enum sensor_channel chan,
282 struct sensor_value *val,
283 struct lsm6ds0_data *data)
284 {
285 return lsm6ds0_accel_get_channel(chan, val, data,
286 LSM6DS0_DEFAULT_ACCEL_FULLSCALE_FACTOR);
287 }
288
lsm6ds0_gyro_convert(struct sensor_value * val,int raw_val,float numerator)289 static inline void lsm6ds0_gyro_convert(struct sensor_value *val, int raw_val,
290 float numerator)
291 {
292 double dval;
293
294 dval = (double)(raw_val) * (double)numerator / 1000.0 * SENSOR_DEG2RAD_DOUBLE;
295 val->val1 = (int32_t)dval;
296 val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
297 }
298
lsm6ds0_gyro_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lsm6ds0_data * data,float numerator)299 static inline int lsm6ds0_gyro_get_channel(enum sensor_channel chan,
300 struct sensor_value *val,
301 struct lsm6ds0_data *data,
302 float numerator)
303 {
304 switch (chan) {
305 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_X_AXIS)
306 case SENSOR_CHAN_GYRO_X:
307 lsm6ds0_gyro_convert(val, data->gyro_sample_x, numerator);
308 break;
309 #endif
310 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Y_AXIS)
311 case SENSOR_CHAN_GYRO_Y:
312 lsm6ds0_gyro_convert(val, data->gyro_sample_y, numerator);
313 break;
314 #endif
315 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Z_AXIS)
316 case SENSOR_CHAN_GYRO_Z:
317 lsm6ds0_gyro_convert(val, data->gyro_sample_z, numerator);
318 break;
319 #endif
320 case SENSOR_CHAN_GYRO_XYZ:
321 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_X_AXIS)
322 lsm6ds0_gyro_convert(val, data->gyro_sample_x, numerator);
323 #endif
324 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Y_AXIS)
325 lsm6ds0_gyro_convert(val + 1, data->gyro_sample_y, numerator);
326 #endif
327 #if defined(CONFIG_LSM6DS0_GYRO_ENABLE_Z_AXIS)
328 lsm6ds0_gyro_convert(val + 2, data->gyro_sample_z, numerator);
329 #endif
330 break;
331 default:
332 return -ENOTSUP;
333 }
334
335 return 0;
336 }
337
lsm6ds0_gyro_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lsm6ds0_data * data)338 static int lsm6ds0_gyro_channel_get(enum sensor_channel chan,
339 struct sensor_value *val,
340 struct lsm6ds0_data *data)
341 {
342 return lsm6ds0_gyro_get_channel(chan, val, data,
343 LSM6DS0_DEFAULT_GYRO_FULLSCALE_FACTOR);
344 }
345
346 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
lsm6ds0_gyro_channel_get_temp(struct sensor_value * val,struct lsm6ds0_data * data)347 static void lsm6ds0_gyro_channel_get_temp(struct sensor_value *val,
348 struct lsm6ds0_data *data)
349 {
350 /* val = temp_sample / 16 + 25 */
351 val->val1 = data->temp_sample / 16 + 25;
352 val->val2 = (data->temp_sample % 16) * (1000000 / 16);
353 }
354 #endif
355
lsm6ds0_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)356 static int lsm6ds0_channel_get(const struct device *dev,
357 enum sensor_channel chan,
358 struct sensor_value *val)
359 {
360 struct lsm6ds0_data *data = dev->data;
361
362 switch (chan) {
363 case SENSOR_CHAN_ACCEL_X:
364 case SENSOR_CHAN_ACCEL_Y:
365 case SENSOR_CHAN_ACCEL_Z:
366 case SENSOR_CHAN_ACCEL_XYZ:
367 lsm6ds0_accel_channel_get(chan, val, data);
368 break;
369 case SENSOR_CHAN_GYRO_X:
370 case SENSOR_CHAN_GYRO_Y:
371 case SENSOR_CHAN_GYRO_Z:
372 case SENSOR_CHAN_GYRO_XYZ:
373 lsm6ds0_gyro_channel_get(chan, val, data);
374 break;
375 #if defined(CONFIG_LSM6DS0_ENABLE_TEMP)
376 case SENSOR_CHAN_DIE_TEMP:
377 lsm6ds0_gyro_channel_get_temp(val, data);
378 break;
379 #endif
380 default:
381 return -ENOTSUP;
382 }
383
384 return 0;
385 }
386
387 static DEVICE_API(sensor, lsm6ds0_api_funcs) = {
388 .sample_fetch = lsm6ds0_sample_fetch,
389 .channel_get = lsm6ds0_channel_get,
390 };
391
lsm6ds0_init_chip(const struct device * dev)392 static int lsm6ds0_init_chip(const struct device *dev)
393 {
394 const struct lsm6ds0_config *config = dev->config;
395 uint8_t chip_id;
396
397 if (lsm6ds0_reboot(dev) < 0) {
398 LOG_DBG("failed to reboot device");
399 return -EIO;
400 }
401
402 if (i2c_reg_read_byte_dt(&config->i2c, LSM6DS0_REG_WHO_AM_I, &chip_id) < 0) {
403 LOG_DBG("failed reading chip id");
404 return -EIO;
405 }
406 if (chip_id != LSM6DS0_VAL_WHO_AM_I) {
407 LOG_DBG("invalid chip id 0x%x", chip_id);
408 return -EIO;
409 }
410 LOG_DBG("chip id 0x%x", chip_id);
411
412 if (lsm6ds0_accel_axis_ctrl(dev, LSM6DS0_ACCEL_ENABLE_X_AXIS,
413 LSM6DS0_ACCEL_ENABLE_Y_AXIS,
414 LSM6DS0_ACCEL_ENABLE_Z_AXIS) < 0) {
415 LOG_DBG("failed to set accelerometer axis");
416 return -EIO;
417 }
418
419 if (lsm6ds0_accel_set_fs_raw(dev, LSM6DS0_DEFAULT_ACCEL_FULLSCALE)
420 < 0) {
421 LOG_DBG("failed to set accelerometer full-scale");
422 return -EIO;
423 }
424
425 if (lsm6ds0_accel_set_odr_raw(dev, LSM6DS0_DEFAULT_ACCEL_SAMPLING_RATE)
426 < 0) {
427 LOG_DBG("failed to set accelerometer sampling rate");
428 return -EIO;
429 }
430
431 if (lsm6ds0_gyro_axis_ctrl(dev, LSM6DS0_GYRO_ENABLE_X_AXIS,
432 LSM6DS0_GYRO_ENABLE_Y_AXIS,
433 LSM6DS0_GYRO_ENABLE_Z_AXIS) < 0) {
434 LOG_DBG("failed to set gyroscope axis");
435 return -EIO;
436 }
437
438 if (lsm6ds0_gyro_set_fs_raw(dev, LSM6DS0_DEFAULT_GYRO_FULLSCALE)
439 < 0) {
440 LOG_DBG("failed to set gyroscope full-scale");
441 return -EIO;
442 }
443
444 if (lsm6ds0_gyro_set_odr_raw(dev, LSM6DS0_DEFAULT_GYRO_SAMPLING_RATE)
445 < 0) {
446 LOG_DBG("failed to set gyroscope sampling rate");
447 return -EIO;
448 }
449
450 if (i2c_reg_update_byte_dt(&config->i2c, LSM6DS0_REG_CTRL_REG8,
451 LSM6DS0_MASK_CTRL_REG8_BDU |
452 LSM6DS0_MASK_CTRL_REG8_BLE |
453 LSM6DS0_MASK_CTRL_REG8_IF_ADD_INC,
454 (1 << LSM6DS0_SHIFT_CTRL_REG8_BDU) |
455 (0 << LSM6DS0_SHIFT_CTRL_REG8_BLE) |
456 (1 << LSM6DS0_SHIFT_CTRL_REG8_IF_ADD_INC))
457 < 0) {
458 LOG_DBG("failed to set BDU, BLE and burst");
459 return -EIO;
460 }
461
462 return 0;
463 }
464
lsm6ds0_init(const struct device * dev)465 static int lsm6ds0_init(const struct device *dev)
466 {
467 const struct lsm6ds0_config * const config = dev->config;
468
469 if (!device_is_ready(config->i2c.bus)) {
470 LOG_ERR("I2C bus device not ready");
471 return -ENODEV;
472 }
473
474 if (lsm6ds0_init_chip(dev) < 0) {
475 LOG_DBG("failed to initialize chip");
476 return -EIO;
477 }
478
479 return 0;
480 }
481
482 #define LSM6DS0_DEFINE(inst) \
483 static struct lsm6ds0_data lsm6ds0_data_##inst; \
484 \
485 static const struct lsm6ds0_config lsm6ds0_config_##inst = { \
486 .i2c = I2C_DT_SPEC_INST_GET(inst), \
487 }; \
488 \
489 SENSOR_DEVICE_DT_INST_DEFINE(inst, lsm6ds0_init, NULL, \
490 &lsm6ds0_data_##inst, &lsm6ds0_config_##inst, POST_KERNEL,\
491 CONFIG_SENSOR_INIT_PRIORITY, &lsm6ds0_api_funcs); \
492
493 DT_INST_FOREACH_STATUS_OKAY(LSM6DS0_DEFINE)
494