1 /*
2  * Copyright (c) 2023 Google LLC
3  * Copyright (c) 2024 Croxel Inc.
4  * Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/logging/log.h>
10 #include <zephyr/rtio/work.h>
11 
12 #include "akm09918c.h"
13 
14 LOG_MODULE_DECLARE(AKM09918C, CONFIG_SENSOR_LOG_LEVEL);
15 
akm09918c_submit_sync(struct rtio_iodev_sqe * iodev_sqe)16 void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
17 {
18 	const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
19 	const struct device *dev = cfg->sensor;
20 	struct akm09918c_data *data = dev->data;
21 	const struct sensor_chan_spec *const channels = cfg->channels;
22 	const size_t num_channels = cfg->count;
23 	int rc;
24 
25 	/* Check if the requested channels are supported */
26 	for (size_t i = 0; i < num_channels; i++) {
27 		switch (channels[i].chan_type) {
28 		case SENSOR_CHAN_MAGN_X:
29 		case SENSOR_CHAN_MAGN_Y:
30 		case SENSOR_CHAN_MAGN_Z:
31 		case SENSOR_CHAN_MAGN_XYZ:
32 		case SENSOR_CHAN_ALL:
33 			break;
34 		default:
35 			LOG_ERR("Unsupported channel type %d", channels[i].chan_type);
36 			rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
37 			return;
38 		}
39 	}
40 
41 	/* start the measurement in the sensor */
42 	rc = akm09918c_start_measurement(dev, SENSOR_CHAN_MAGN_XYZ);
43 	if (rc != 0) {
44 		LOG_ERR("Failed to fetch samples.");
45 		rtio_iodev_sqe_err(iodev_sqe, rc);
46 		return;
47 	}
48 
49 	/* save information for the work item */
50 	data->work_ctx.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
51 	data->work_ctx.iodev_sqe = iodev_sqe;
52 
53 	rc = k_work_schedule(&data->work_ctx.async_fetch_work, K_USEC(AKM09918C_MEASURE_TIME_US));
54 	if (rc == 0) {
55 		LOG_ERR("The last fetch has not finished yet. "
56 			"Try again later when the last sensor read operation has finished.");
57 		rtio_iodev_sqe_err(iodev_sqe, -EBUSY);
58 	}
59 	return;
60 }
61 
akm09918c_submit(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)62 void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
63 {
64 	struct rtio_work_req *req = rtio_work_req_alloc();
65 
66 	if (req == NULL) {
67 		LOG_ERR("RTIO work item allocation failed. Consider to increase "
68 			"CONFIG_RTIO_WORKQ_POOL_ITEMS.");
69 		rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
70 		return;
71 	}
72 
73 	rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync);
74 }
75 
akm09918_async_fetch(struct k_work * work)76 void akm09918_async_fetch(struct k_work *work)
77 {
78 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
79 	struct akm09918c_async_fetch_ctx *ctx =
80 		CONTAINER_OF(dwork, struct akm09918c_async_fetch_ctx, async_fetch_work);
81 	const struct sensor_read_config *cfg = ctx->iodev_sqe->sqe.iodev->data;
82 	const struct device *dev = cfg->sensor;
83 	uint32_t req_buf_len = sizeof(struct akm09918c_encoded_data);
84 	uint32_t buf_len;
85 	uint8_t *buf;
86 	struct akm09918c_encoded_data *edata;
87 	int rc;
88 
89 	/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
90 	rc = rtio_sqe_rx_buf(ctx->iodev_sqe, req_buf_len, req_buf_len, &buf, &buf_len);
91 	if (rc != 0) {
92 		LOG_ERR("Failed to get a read buffer of size %u bytes", req_buf_len);
93 		rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
94 		return;
95 	}
96 	edata = (struct akm09918c_encoded_data *)buf;
97 	rc = akm09918c_fetch_measurement(dev, &edata->readings[0], &edata->readings[1],
98 					 &edata->readings[2]);
99 	if (rc != 0) {
100 		rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
101 		return;
102 	}
103 	rtio_iodev_sqe_ok(ctx->iodev_sqe, 0);
104 }
105