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 #include <zephyr/drivers/sensor.h>
10 #include "lsm6dsv16x.h"
11 #include "lsm6dsv16x_rtio.h"
12 #include "lsm6dsv16x_decoder.h"
13 #include <zephyr/rtio/work.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(LSM6DSV16X_RTIO, CONFIG_SENSOR_LOG_LEVEL);
17 
lsm6dsv16x_submit_sample(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)18 static void lsm6dsv16x_submit_sample(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
19 {
20 	const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
21 	const struct sensor_chan_spec *const channels = cfg->channels;
22 	const size_t num_channels = cfg->count;
23 	uint32_t min_buf_len = sizeof(struct lsm6dsv16x_rtio_data);
24 	int rc = 0;
25 	uint8_t *buf;
26 	uint32_t buf_len;
27 	struct lsm6dsv16x_rtio_data *edata;
28 	struct lsm6dsv16x_data *data = dev->data;
29 
30 	const struct lsm6dsv16x_config *config = dev->config;
31 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx;
32 
33 	/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
34 	rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len);
35 	if (rc != 0) {
36 		LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len);
37 		goto err;
38 	}
39 
40 	edata = (struct lsm6dsv16x_rtio_data *)buf;
41 
42 	edata->has_accel = 0;
43 	edata->has_gyro = 0;
44 	edata->has_temp = 0;
45 
46 	for (int i = 0; i < num_channels; i++) {
47 		switch (channels[i].chan_type) {
48 		case SENSOR_CHAN_ACCEL_X:
49 		case SENSOR_CHAN_ACCEL_Y:
50 		case SENSOR_CHAN_ACCEL_Z:
51 		case SENSOR_CHAN_ACCEL_XYZ:
52 			edata->has_accel = 1;
53 
54 			rc = lsm6dsv16x_acceleration_raw_get(ctx, edata->acc);
55 			if (rc  < 0) {
56 				LOG_DBG("Failed to read accel sample");
57 				goto err;
58 			}
59 			break;
60 		case SENSOR_CHAN_GYRO_X:
61 		case SENSOR_CHAN_GYRO_Y:
62 		case SENSOR_CHAN_GYRO_Z:
63 		case SENSOR_CHAN_GYRO_XYZ:
64 			edata->has_gyro = 1;
65 
66 			rc = lsm6dsv16x_angular_rate_raw_get(ctx, edata->gyro);
67 			if (rc  < 0) {
68 				LOG_DBG("Failed to read gyro sample");
69 				goto err;
70 			}
71 			break;
72 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
73 		case SENSOR_CHAN_DIE_TEMP:
74 			edata->has_temp = 1;
75 
76 			rc = lsm6dsv16x_temperature_raw_get(ctx, &edata->temp);
77 			if (rc < 0) {
78 				LOG_DBG("Failed to read temp sample");
79 				goto err;
80 			}
81 			break;
82 #endif
83 		case SENSOR_CHAN_ALL:
84 			edata->has_accel = 1;
85 
86 			rc = lsm6dsv16x_acceleration_raw_get(ctx, edata->acc);
87 			if (rc  < 0) {
88 				LOG_DBG("Failed to read accel sample");
89 				goto err;
90 			}
91 
92 			edata->has_gyro = 1;
93 
94 			rc = lsm6dsv16x_angular_rate_raw_get(ctx, edata->gyro);
95 			if (rc  < 0) {
96 				LOG_DBG("Failed to read gyro sample");
97 				goto err;
98 			}
99 
100 #if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
101 			edata->has_temp = 1;
102 
103 			rc = lsm6dsv16x_temperature_raw_get(ctx, &edata->temp);
104 			if (rc < 0) {
105 				LOG_DBG("Failed to read temp sample");
106 				goto err;
107 			}
108 #endif
109 			break;
110 		default:
111 			continue;
112 		}
113 	}
114 
115 	edata->header.is_fifo = false;
116 	edata->header.accel_fs = data->accel_fs;
117 	edata->header.gyro_fs = data->gyro_fs;
118 	edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
119 
120 	rtio_iodev_sqe_ok(iodev_sqe, 0);
121 
122 err:
123 	/* Check that the fetch succeeded */
124 	if (rc != 0) {
125 		LOG_ERR("Failed to fetch samples");
126 		rtio_iodev_sqe_err(iodev_sqe, rc);
127 		return;
128 	}
129 }
130 
lsm6dsv16x_submit_sync(struct rtio_iodev_sqe * iodev_sqe)131 void lsm6dsv16x_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
132 {
133 	const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
134 	const struct device *dev = cfg->sensor;
135 
136 	if (!cfg->is_streaming) {
137 		lsm6dsv16x_submit_sample(dev, iodev_sqe);
138 	} else if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) {
139 		lsm6dsv16x_submit_stream(dev, iodev_sqe);
140 	} else {
141 		rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
142 	}
143 }
144 
lsm6dsv16x_submit(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)145 void lsm6dsv16x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
146 {
147 	struct rtio_work_req *req = rtio_work_req_alloc();
148 
149 	if (req == NULL) {
150 		LOG_ERR("RTIO work item allocation failed. Consider to increase "
151 			"CONFIG_RTIO_WORKQ_POOL_ITEMS.");
152 		rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
153 		return;
154 	}
155 
156 	rtio_work_req_submit(req, iodev_sqe, lsm6dsv16x_submit_sync);
157 }
158