1 /* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver
2 *
3 * Copyright (c) 2023 Google LLC
4 * Copyright (c) 2024 STMicroelectronics
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define DT_DRV_COMPAT st_lsm6dsv16x
10
11 #include <zephyr/dt-bindings/sensor/lsm6dsv16x.h>
12 #include <zephyr/drivers/sensor.h>
13 #include "lsm6dsv16x.h"
14 #include "lsm6dsv16x_decoder.h"
15 #include <zephyr/rtio/work.h>
16 #include <zephyr/drivers/sensor_clock.h>
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_DECLARE(LSM6DSV16X_RTIO);
20
21 #define FIFO_TH 1
22 #define FIFO_FULL 2
23
lsm6dsv16x_config_fifo(const struct device * dev,uint8_t fifo_irq)24 static void lsm6dsv16x_config_fifo(const struct device *dev, uint8_t fifo_irq)
25 {
26 struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
27 const struct lsm6dsv16x_config *config = dev->config;
28 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx;
29 uint8_t fifo_wtm = 0;
30 lsm6dsv16x_pin_int_route_t pin_int = { 0 };
31 lsm6dsv16x_fifo_xl_batch_t xl_batch = LSM6DSV16X_DT_XL_NOT_BATCHED;
32 lsm6dsv16x_fifo_gy_batch_t gy_batch = LSM6DSV16X_DT_GY_NOT_BATCHED;
33 lsm6dsv16x_fifo_temp_batch_t temp_batch = LSM6DSV16X_DT_TEMP_NOT_BATCHED;
34 lsm6dsv16x_fifo_mode_t fifo_mode = LSM6DSV16X_BYPASS_MODE;
35 lsm6dsv16x_sflp_data_rate_t sflp_odr = LSM6DSV16X_SFLP_120Hz;
36 lsm6dsv16x_fifo_sflp_raw_t sflp_fifo = { 0 };
37
38 /* disable FIFO as first thing */
39 lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE);
40
41 pin_int.fifo_th = PROPERTY_DISABLE;
42 pin_int.fifo_full = PROPERTY_DISABLE;
43
44 if (fifo_irq != 0) {
45 pin_int.fifo_th = (fifo_irq & FIFO_TH) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
46 pin_int.fifo_full = (fifo_irq & FIFO_FULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
47
48 xl_batch = config->accel_batch;
49 gy_batch = config->gyro_batch;
50 temp_batch = config->temp_batch;
51
52 fifo_mode = LSM6DSV16X_STREAM_MODE;
53 fifo_wtm = config->fifo_wtm;
54
55 if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION) {
56 sflp_fifo.game_rotation = 1;
57 }
58
59 if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GRAVITY) {
60 sflp_fifo.gravity = 1;
61 }
62
63 if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GBIAS) {
64 sflp_fifo.gbias = 1;
65 }
66
67 sflp_odr = config->sflp_odr;
68 }
69
70 /*
71 * Set FIFO watermark (number of unread sensor data TAG + 6 bytes
72 * stored in FIFO) to FIFO_WATERMARK samples
73 */
74 lsm6dsv16x_fifo_watermark_set(ctx, config->fifo_wtm);
75
76 /* Turn on/off FIFO */
77 lsm6dsv16x_fifo_mode_set(ctx, fifo_mode);
78
79 /* Set FIFO batch rates */
80 lsm6dsv16x_fifo_xl_batch_set(ctx, xl_batch);
81 lsm6dsv16x->accel_batch_odr = xl_batch;
82 lsm6dsv16x_fifo_gy_batch_set(ctx, gy_batch);
83 lsm6dsv16x->gyro_batch_odr = gy_batch;
84 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
85 lsm6dsv16x_fifo_temp_batch_set(ctx, temp_batch);
86 lsm6dsv16x->temp_batch_odr = temp_batch;
87 #endif
88
89 lsm6dsv16x_sflp_data_rate_set(ctx, sflp_odr);
90 lsm6dsv16x->sflp_batch_odr = sflp_odr;
91 lsm6dsv16x_fifo_sflp_batch_set(ctx, sflp_fifo);
92 lsm6dsv16x_sflp_game_rotation_set(ctx, PROPERTY_ENABLE);
93
94 /* Set pin interrupt (fifo_th could be on or off) */
95 if ((config->drdy_pin == 1) || (ON_I3C_BUS(config) && (!I3C_INT_PIN(config)))) {
96 lsm6dsv16x_pin_int1_route_set(ctx, &pin_int);
97 } else {
98 lsm6dsv16x_pin_int2_route_set(ctx, &pin_int);
99 }
100 }
101
lsm6dsv16x_submit_stream(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)102 void lsm6dsv16x_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
103 {
104 struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
105 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
106 const struct lsm6dsv16x_config *config = dev->config;
107 #endif
108 const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
109 uint8_t fifo_irq = 0;
110
111 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
112 gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_DISABLE);
113 }
114
115 for (size_t i = 0; i < cfg->count; i++) {
116 if (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) {
117 fifo_irq = FIFO_TH;
118 } else if (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL) {
119 fifo_irq = FIFO_FULL;
120 }
121 }
122
123 /* if any change in fifo irq */
124 if (fifo_irq != lsm6dsv16x->fifo_irq) {
125 lsm6dsv16x->fifo_irq = fifo_irq;
126
127 /* enable/disable the FIFO */
128 lsm6dsv16x_config_fifo(dev, fifo_irq);
129 }
130
131 lsm6dsv16x->streaming_sqe = iodev_sqe;
132
133 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
134 gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE);
135 }
136 }
137
lsm6dsv16x_complete_op_cb(struct rtio * r,const struct rtio_sqe * sqe,void * arg)138 static void lsm6dsv16x_complete_op_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg)
139 {
140 const struct device *dev = arg;
141 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
142 const struct lsm6dsv16x_config *config = dev->config;
143 #endif
144 struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
145
146 /*
147 * Mark operation completed
148 */
149 rtio_iodev_sqe_ok(sqe->userdata, 0);
150 lsm6dsv16x->streaming_sqe = NULL;
151 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
152 gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE);
153 }
154 }
155
lsm6dsv16x_read_fifo_cb(struct rtio * r,const struct rtio_sqe * sqe,void * arg)156 static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg)
157 {
158 const struct device *dev = arg;
159 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
160 const struct lsm6dsv16x_config *config = dev->config;
161 #endif
162 struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
163 struct gpio_dt_spec *irq_gpio = lsm6dsv16x->drdy_gpio;
164 struct rtio_iodev *iodev = lsm6dsv16x->iodev;
165 struct sensor_read_config *read_config;
166 uint8_t fifo_th = 0, fifo_full = 0;
167 uint16_t fifo_count;
168
169 /* At this point, no sqe request is queued should be considered as a bug */
170 __ASSERT_NO_MSG(lsm6dsv16x->streaming_sqe != NULL);
171
172 read_config = (struct sensor_read_config *)lsm6dsv16x->streaming_sqe->sqe.iodev->data;
173 __ASSERT_NO_MSG(read_config != NULL);
174 __ASSERT_NO_MSG(read_config->is_streaming == true);
175
176 /* parse the configuration in search for any configured trigger */
177 struct sensor_stream_trigger *fifo_ths_cfg = NULL;
178 struct sensor_stream_trigger *fifo_full_cfg = NULL;
179
180 for (int i = 0; i < read_config->count; ++i) {
181 if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) {
182 fifo_ths_cfg = &read_config->triggers[i];
183 continue;
184 }
185
186 if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL) {
187 fifo_full_cfg = &read_config->triggers[i];
188 continue;
189 }
190 }
191
192 /* fill fifo h/w status */
193 fifo_th = (lsm6dsv16x->fifo_status[1] & 0x80) ? 1 : 0;
194 fifo_full = (lsm6dsv16x->fifo_status[1] & 0x20) ? 1 : 0;
195 fifo_count = (uint16_t)lsm6dsv16x->fifo_status[1] & 0x1U;
196 fifo_count = (fifo_count << 8) | lsm6dsv16x->fifo_status[0];
197 lsm6dsv16x->fifo_count = fifo_count;
198
199 bool has_fifo_ths_trig = fifo_ths_cfg != NULL && fifo_th == 1;
200 bool has_fifo_full_trig = fifo_full_cfg != NULL && fifo_full == 1;
201
202 /* check if no theshold/full fifo interrupt or spurious interrupts */
203 if (!has_fifo_ths_trig && !has_fifo_full_trig) {
204 /* complete operation with no error */
205 rtio_iodev_sqe_ok(sqe->userdata, 0);
206
207 lsm6dsv16x->streaming_sqe = NULL;
208 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
209 gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
210 }
211 return;
212 }
213
214 struct rtio_cqe *cqe;
215 int res = 0;
216
217 do {
218 cqe = rtio_cqe_consume(lsm6dsv16x->rtio_ctx);
219 if (cqe != NULL) {
220 if ((cqe->result < 0) && (res == 0)) {
221 LOG_ERR("Bus error: %d", cqe->result);
222 res = cqe->result;
223 }
224 rtio_cqe_release(lsm6dsv16x->rtio_ctx, cqe);
225 }
226 } while (cqe != NULL);
227
228 /* Bail/cancel attempt to read sensor on any error */
229 if (res != 0) {
230 rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, res);
231 lsm6dsv16x->streaming_sqe = NULL;
232 return;
233 }
234
235 enum sensor_stream_data_opt data_opt;
236
237 if (has_fifo_ths_trig && !has_fifo_full_trig) {
238 /* Only care about fifo threshold */
239 data_opt = fifo_ths_cfg->opt;
240 } else if (!has_fifo_ths_trig && has_fifo_full_trig) {
241 /* Only care about fifo full */
242 data_opt = fifo_full_cfg->opt;
243 } else {
244 /* Both fifo threshold and full */
245 data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt);
246 }
247
248 if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) {
249 uint8_t *buf;
250 uint32_t buf_len;
251
252 /* Clear streaming_sqe since we're done with the call */
253 if (rtio_sqe_rx_buf(lsm6dsv16x->streaming_sqe, sizeof(struct lsm6dsv16x_fifo_data),
254 sizeof(struct lsm6dsv16x_fifo_data), &buf, &buf_len) != 0) {
255 rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, -ENOMEM);
256 lsm6dsv16x->streaming_sqe = NULL;
257 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
258 gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
259 }
260 return;
261 }
262
263 struct lsm6dsv16x_fifo_data *rx_data = (struct lsm6dsv16x_fifo_data *)buf;
264
265 memset(buf, 0, buf_len);
266 rx_data->header.is_fifo = 1;
267 rx_data->header.timestamp = lsm6dsv16x->fifo_timestamp;
268 rx_data->int_status = lsm6dsv16x->fifo_status[1];
269 rx_data->fifo_count = 0;
270
271 /* complete request with ok */
272 rtio_iodev_sqe_ok(lsm6dsv16x->streaming_sqe, 0);
273 lsm6dsv16x->streaming_sqe = NULL;
274 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
275 gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
276 }
277
278 if (data_opt == SENSOR_STREAM_DATA_DROP) {
279
280 /*
281 * Flush the FIFO by setting the mode to LSM6DSV16X_BYPASS_MODE
282 *
283 * STMEMSC API equivalent code:
284 *
285 * lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE);
286 */
287 struct rtio_sqe *write_fifo_mode = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
288 uint8_t lsm6dsv16x_fifo_mode_set[] = {
289 LSM6DSV16X_FIFO_CTRL4,
290 LSM6DSV16X_BYPASS_MODE,
291 };
292
293 write_fifo_mode->flags |= RTIO_SQE_NO_RESPONSE;
294 rtio_sqe_prep_tiny_write(write_fifo_mode, iodev,
295 RTIO_PRIO_NORM, lsm6dsv16x_fifo_mode_set,
296 ARRAY_SIZE(lsm6dsv16x_fifo_mode_set), NULL);
297
298 rtio_submit(lsm6dsv16x->rtio_ctx, 0);
299 }
300
301 return;
302 }
303
304 uint8_t *buf, *read_buf;
305 uint32_t buf_len, buf_avail;
306 uint32_t req_len = LSM6DSV16X_FIFO_SIZE(fifo_count) + sizeof(struct lsm6dsv16x_fifo_data);
307
308 if (rtio_sqe_rx_buf(lsm6dsv16x->streaming_sqe, req_len, req_len, &buf, &buf_len) != 0) {
309 LOG_ERR("Failed to get buffer");
310 rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, -ENOMEM);
311 lsm6dsv16x->streaming_sqe = NULL;
312 if (!ON_I3C_BUS(config) || (I3C_INT_PIN(config))) {
313 gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
314 }
315 return;
316 }
317
318 struct lsm6dsv16x_fifo_data hdr = {
319 .header = {
320 .is_fifo = true,
321 .accel_fs = lsm6dsv16x->accel_fs,
322 .gyro_fs = lsm6dsv16x->gyro_fs,
323 .timestamp = lsm6dsv16x->fifo_timestamp,
324 },
325 .fifo_count = fifo_count,
326 .accel_batch_odr = lsm6dsv16x->accel_batch_odr,
327 .gyro_batch_odr = lsm6dsv16x->gyro_batch_odr,
328 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
329 .temp_batch_odr = lsm6dsv16x->temp_batch_odr,
330 #endif
331 .sflp_batch_odr = lsm6dsv16x->sflp_batch_odr,
332 };
333
334 memcpy(buf, &hdr, sizeof(hdr));
335 read_buf = buf + sizeof(hdr);
336 buf_avail = buf_len - sizeof(hdr);
337
338 /*
339 * Prepare rtio enabled bus to read all fifo_count entries from
340 * LSM6DSV16X_FIFO_DATA_OUT_TAG. Then lsm6dsv16x_complete_op_cb
341 * callback will be invoked.
342 *
343 * STMEMSC API equivalent code:
344 *
345 * num = fifo_status.fifo_level;
346 *
347 * while (num--) {
348 * lsm6dsv16x_fifo_out_raw_t f_data;
349 *
350 * lsm6dsv16x_fifo_out_raw_get(&dev_ctx, &f_data);
351 * }
352 */
353 struct rtio_sqe *write_fifo_dout_addr = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
354 struct rtio_sqe *read_fifo_dout_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
355 struct rtio_sqe *complete_op = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
356 uint8_t reg = lsm6dsv16x_bus_reg(lsm6dsv16x, LSM6DSV16X_FIFO_DATA_OUT_TAG);
357
358 rtio_sqe_prep_tiny_write(write_fifo_dout_addr, iodev, RTIO_PRIO_NORM, ®, 1, NULL);
359 write_fifo_dout_addr->flags = RTIO_SQE_TRANSACTION;
360 rtio_sqe_prep_read(read_fifo_dout_reg, iodev, RTIO_PRIO_NORM,
361 read_buf, buf_avail, lsm6dsv16x->streaming_sqe);
362 read_fifo_dout_reg->flags = RTIO_SQE_CHAINED;
363 if (lsm6dsv16x->bus_type == BUS_I2C) {
364 read_fifo_dout_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
365 } else if (lsm6dsv16x->bus_type == BUS_I3C) {
366 read_fifo_dout_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
367 }
368 rtio_sqe_prep_callback_no_cqe(complete_op, lsm6dsv16x_complete_op_cb, (void *)dev,
369 lsm6dsv16x->streaming_sqe);
370
371 rtio_submit(lsm6dsv16x->rtio_ctx, 0);
372 }
373
lsm6dsv16x_stream_irq_handler(const struct device * dev)374 void lsm6dsv16x_stream_irq_handler(const struct device *dev)
375 {
376 struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
377 struct rtio_iodev *iodev = lsm6dsv16x->iodev;
378 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
379 const struct lsm6dsv16x_config *config = dev->config;
380 #endif
381 uint64_t cycles;
382 int rc;
383
384 if (lsm6dsv16x->streaming_sqe == NULL) {
385 return;
386 }
387
388 rc = sensor_clock_get_cycles(&cycles);
389 if (rc != 0) {
390 LOG_ERR("Failed to get sensor clock cycles");
391 rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, rc);
392 return;
393 }
394
395 /* get timestamp as soon as the irq is served */
396 lsm6dsv16x->fifo_timestamp = sensor_clock_cycles_to_ns(cycles);
397
398 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
399 if (ON_I3C_BUS(config) && (!I3C_INT_PIN(config))) {
400 /*
401 * If we are on an I3C bus, then it should be expected that the fifo status was
402 * already received in the IBI payload and we don't need to read it again.
403 */
404 lsm6dsv16x->fifo_status[0] = lsm6dsv16x->ibi_payload.fifo_status1;
405 lsm6dsv16x->fifo_status[1] = lsm6dsv16x->ibi_payload.fifo_status2;
406 } else
407 #endif
408 {
409 lsm6dsv16x->fifo_status[0] = lsm6dsv16x->fifo_status[1] = 0;
410
411 /*
412 * Prepare rtio enabled bus to read LSM6DSV16X_FIFO_STATUS1 and
413 * LSM6DSV16X_FIFO_STATUS2 registers where FIFO threshold condition and count are
414 * reported. Then lsm6dsv16x_read_fifo_cb callback will be invoked.
415 *
416 * STMEMSC API equivalent code:
417 *
418 * lsm6dsv16x_fifo_status_t fifo_status;
419 *
420 * lsm6dsv16x_fifo_status_get(&dev_ctx, &fifo_status);
421 */
422 struct rtio_sqe *write_fifo_status_addr = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
423 struct rtio_sqe *read_fifo_status_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
424 uint8_t reg = lsm6dsv16x_bus_reg(lsm6dsv16x, LSM6DSV16X_FIFO_STATUS1);
425
426 rtio_sqe_prep_tiny_write(write_fifo_status_addr, iodev, RTIO_PRIO_NORM, ®, 1,
427 NULL);
428 write_fifo_status_addr->flags = RTIO_SQE_TRANSACTION;
429 rtio_sqe_prep_read(read_fifo_status_reg, iodev, RTIO_PRIO_NORM,
430 lsm6dsv16x->fifo_status, 2, NULL);
431 read_fifo_status_reg->flags = RTIO_SQE_CHAINED;
432 if (lsm6dsv16x->bus_type == BUS_I2C) {
433 read_fifo_status_reg->iodev_flags |=
434 RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
435 } else if (lsm6dsv16x->bus_type == BUS_I3C) {
436 read_fifo_status_reg->iodev_flags |=
437 RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
438 }
439 }
440 struct rtio_sqe *check_fifo_status_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx);
441
442 rtio_sqe_prep_callback_no_cqe(check_fifo_status_reg,
443 lsm6dsv16x_read_fifo_cb, (void *)dev, NULL);
444 rtio_submit(lsm6dsv16x->rtio_ctx, 0);
445 }
446