Commit 91af849c authored by Florian Weber's avatar Florian Weber Committed by Carles Cufi
Browse files

drivers: sensor: ak09918c use RTIO



make usage of the RTIO in the ak09918c driver

Signed-off-by: default avatarFlorian Weber <Florian.Weber@live.de>
parent 4e9bd00d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ config AKM09918C
	default y
	depends on DT_HAS_ASAHI_KASEI_AKM09918C_ENABLED
	select I2C
	select I2C_RTIO if SENSOR_ASYNC_API
	select RTIO_WORKQ if SENSOR_ASYNC_API
	help
	  Enable driver for AK8975 magnetometer.
+13 −6
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(AKM09918C, CONFIG_SENSOR_LOG_LEVEL);
 * @param chan Channel ID for starting the measurement
 * @return int 0 if successful or error code
 */
int akm09918c_start_measurement(const struct device *dev, enum sensor_channel chan)
int akm09918c_start_measurement_blocking(const struct device *dev, enum sensor_channel chan)
{
	struct akm09918c_data *data = dev->data;
	const struct akm09918c_config *cfg = dev->config;
@@ -59,7 +59,8 @@ int akm09918c_start_measurement(const struct device *dev, enum sensor_channel ch
 * @param z Location to write Z channel sample.
 * @return int 0 if successful or error code
 */
int akm09918c_fetch_measurement(const struct device *dev, int16_t *x, int16_t *y, int16_t *z)
int akm09918c_fetch_measurement_blocking(const struct device *dev, int16_t *x, int16_t *y,
					 int16_t *z)
{
	const struct akm09918c_config *cfg = dev->config;
	uint8_t buf[9] = {0};
@@ -86,7 +87,7 @@ static int akm09918c_sample_fetch(const struct device *dev, enum sensor_channel
{
	struct akm09918c_data *data = dev->data;

	int ret = akm09918c_start_measurement(dev, chan);
	int ret = akm09918c_start_measurement_blocking(dev, chan);

	if (ret) {
		return ret;
@@ -95,7 +96,8 @@ static int akm09918c_sample_fetch(const struct device *dev, enum sensor_channel
	LOG_DBG("Waiting for sample...");
	k_usleep(AKM09918C_MEASURE_TIME_US);

	return akm09918c_fetch_measurement(dev, &data->x_sample, &data->y_sample, &data->z_sample);
	return akm09918c_fetch_measurement_blocking(dev, &data->x_sample, &data->y_sample,
						    &data->z_sample);
}

static void akm09918c_convert(struct sensor_value *val, int16_t sample)
@@ -249,8 +251,13 @@ static DEVICE_API(sensor, akm09918c_driver_api) = {
};

#define AKM09918C_DEFINE(inst)                                                                     \
	static struct akm09918c_data akm09918c_data_##inst;                                        \
                                                                                                   \
	IF_ENABLED(CONFIG_I2C_RTIO, \
		(I2C_DT_IODEV_DEFINE(akm09918c_iodev_##inst, DT_DRV_INST(inst));)) \
	IF_ENABLED(CONFIG_I2C_RTIO, (RTIO_DEFINE( \
		akm09918c_rtio_ctx_##inst, CONFIG_I2C_RTIO_SQ_SIZE, CONFIG_I2C_RTIO_CQ_SIZE);)) \
	static struct akm09918c_data akm09918c_data_##inst = {                                     \
		IF_ENABLED(CONFIG_I2C_RTIO, (.rtio_ctx = \
			&akm09918c_rtio_ctx_##inst, .iodev = &akm09918c_iodev_##inst)) }; \
	static const struct akm09918c_config akm09918c_config_##inst = {                           \
		.i2c = I2C_DT_SPEC_INST_GET(inst),                                                 \
	};                                                                                         \
+14 −3
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ struct akm09918c_data {
		uint64_t timestamp;
		struct k_work_delayable async_fetch_work;
	} work_ctx;
	/* for communication to the bus controller */
	struct rtio *rtio_ctx;
	struct rtio_iodev *iodev;
#endif
};

@@ -82,9 +85,10 @@ static inline void akm09918c_reg_to_hz(uint8_t reg, struct sensor_value *val)
		break;
	}
}
int akm09918c_start_measurement(const struct device *dev, enum sensor_channel chan);
int akm09918c_start_measurement_blocking(const struct device *dev, enum sensor_channel chan);

int akm09918c_fetch_measurement(const struct device *dev, int16_t *x, int16_t *y, int16_t *z);
int akm09918c_fetch_measurement_blocking(const struct device *dev, int16_t *x, int16_t *y,
					 int16_t *z);
/*
 * RTIO types
 */
@@ -95,7 +99,12 @@ struct akm09918c_decoder_header {

struct akm09918c_encoded_data {
	struct akm09918c_decoder_header header;
	int16_t readings[3];
	struct __packed {
		uint8_t st1;
		int16_t data[3];
		uint8_t tmps; /* not used  - only for padding */
		uint8_t st2;  /* not used but includes overflow data */
	} reading;
};

void akm09918_async_fetch(struct k_work *work);
@@ -103,5 +112,7 @@ void akm09918_async_fetch(struct k_work *work);
int akm09918c_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder);

void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe);
void akm09918_after_start_cb(struct rtio *rtio_ctx, const struct rtio_sqe *sqe, void *arg0);
void akm09918_complete_cb(struct rtio *rtio_ctx, const struct rtio_sqe *sqe, void *arg0);

#endif /* ZEPHYR_DRIVERS_SENSOR_AKM09918C_AKM09918C_H_ */
+93 −29
Original line number Diff line number Diff line
@@ -7,22 +7,39 @@
 */

#include <zephyr/logging/log.h>
#include <zephyr/rtio/work.h>
#include <zephyr/rtio/rtio.h>
#include <zephyr/drivers/sensor_clock.h>
#include <zephyr/sys/byteorder.h>

#include "akm09918c.h"

LOG_MODULE_DECLARE(AKM09918C, CONFIG_SENSOR_LOG_LEVEL);

void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
static int akm09918c_flush_cqes(struct rtio *rtio_ctx)
{
	/* Flush completions */
	struct rtio_cqe *cqe;
	int res = 0;

	do {
		cqe = rtio_cqe_consume(rtio_ctx);
		if (cqe != NULL) {
			if ((cqe->result < 0 && res == 0)) {
				LOG_ERR("Bus error: %d", cqe->result);
				res = cqe->result;
			}
			rtio_cqe_release(rtio_ctx, cqe);
		}
	} while (cqe != NULL);
	return res;
}

void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
{
	const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
	const struct device *dev = cfg->sensor;
	struct akm09918c_data *data = dev->data;
	const struct sensor_chan_spec *const channels = cfg->channels;
	const size_t num_channels = cfg->count;
	uint64_t cycles;
	int rc;

	/* Check if the requested channels are supported */
	for (size_t i = 0; i < num_channels; i++) {
@@ -39,15 +56,31 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
			return;
		}
	}
	struct rtio_sqe *writeByte_sqe = i2c_rtio_copy_reg_write_byte(
		data->rtio_ctx, data->iodev, AKM09918C_REG_CNTL2, AKM09918C_CNTL2_SINGLE_MEASURE);
	struct rtio_sqe *cb_sqe = rtio_sqe_acquire(data->rtio_ctx);

	/* start the measurement in the sensor */
	rc = akm09918c_start_measurement(dev, SENSOR_CHAN_MAGN_XYZ);
	if (rc != 0) {
		LOG_ERR("Failed to fetch samples.");
		rtio_iodev_sqe_err(iodev_sqe, rc);
		return;
	writeByte_sqe->flags |= RTIO_SQE_CHAINED;
	rtio_sqe_prep_callback_no_cqe(cb_sqe, akm09918_after_start_cb, (void *)iodev_sqe, NULL);

	if (writeByte_sqe != NULL && cb_sqe != NULL) {
		rtio_submit(data->rtio_ctx, 0);
	} else {
		rtio_sqe_drop_all(data->rtio_ctx);
		rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
	}
}

void akm09918_after_start_cb(struct rtio *rtio_ctx, const struct rtio_sqe *sqe, void *arg0)
{
	const struct rtio_iodev_sqe *parent_iodev_sqe = (struct rtio_iodev_sqe *)arg0;
	const struct sensor_read_config *cfg = parent_iodev_sqe->sqe.iodev->data;
	const struct device *dev = cfg->sensor;
	struct akm09918c_data *data = dev->data;
	struct rtio_iodev_sqe *iodev_sqe = (struct rtio_iodev_sqe *)arg0;
	uint64_t cycles;
	int rc;

	rc = sensor_clock_get_cycles(&cycles);
	if (rc != 0) {
		LOG_ERR("Failed to get sensor clock cycles");
@@ -59,6 +92,12 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
	data->work_ctx.timestamp = sensor_clock_cycles_to_ns(cycles);
	data->work_ctx.iodev_sqe = iodev_sqe;

	rc = akm09918c_flush_cqes(data->rtio_ctx);
	if (rc != 0) {
		rtio_iodev_sqe_err(iodev_sqe, rc);
		return;
	}

	rc = k_work_schedule(&data->work_ctx.async_fetch_work, K_USEC(AKM09918C_MEASURE_TIME_US));
	if (rc == 0) {
		LOG_ERR("The last fetch has not finished yet. "
@@ -68,20 +107,6 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
	return;
}

void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
{
	struct rtio_work_req *req = rtio_work_req_alloc();

	if (req == NULL) {
		LOG_ERR("RTIO work item allocation failed. Consider to increase "
			"CONFIG_RTIO_WORKQ_POOL_ITEMS.");
		rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
		return;
	}

	rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync);
}

void akm09918_async_fetch(struct k_work *work)
{
	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
@@ -89,6 +114,7 @@ void akm09918_async_fetch(struct k_work *work)
		CONTAINER_OF(dwork, struct akm09918c_async_fetch_ctx, async_fetch_work);
	const struct sensor_read_config *cfg = ctx->iodev_sqe->sqe.iodev->data;
	const struct device *dev = cfg->sensor;
	struct akm09918c_data *data = dev->data;
	uint32_t req_buf_len = sizeof(struct akm09918c_encoded_data);
	uint32_t buf_len;
	uint8_t *buf;
@@ -103,11 +129,49 @@ void akm09918_async_fetch(struct k_work *work)
		return;
	}
	edata = (struct akm09918c_encoded_data *)buf;
	rc = akm09918c_fetch_measurement(dev, &edata->readings[0], &edata->readings[1],
					 &edata->readings[2]);

	struct rtio_sqe *burstRead_sqe =
		i2c_rtio_copy_reg_burst_read(data->rtio_ctx, data->iodev, AKM09918C_REG_ST1,
					     &(edata->reading), sizeof(edata->reading));

	edata->header.timestamp = ctx->timestamp;

	struct rtio_sqe *cb_sqe = rtio_sqe_acquire(data->rtio_ctx);

	rtio_sqe_prep_callback_no_cqe(cb_sqe, akm09918_complete_cb, (void *)ctx->iodev_sqe, NULL);

	if (burstRead_sqe != NULL && cb_sqe != NULL) {
		burstRead_sqe->flags |= RTIO_SQE_CHAINED;
		rtio_submit(data->rtio_ctx, 0);
	} else {
		rtio_sqe_drop_all(data->rtio_ctx);
		rtio_iodev_sqe_err(ctx->iodev_sqe, -ENOMEM);
	}
}

void akm09918_complete_cb(struct rtio *rtio_ctx, const struct rtio_sqe *sqe, void *arg0)
{
	struct rtio_iodev_sqe *parent_iodev_sqe = (struct rtio_iodev_sqe *)arg0;
	struct rtio_sqe *parent_sqe = &parent_iodev_sqe->sqe;
	struct akm09918c_encoded_data *edata =
		(struct akm09918c_encoded_data *)(parent_sqe->rx.buf);
	int rc;

	rc = akm09918c_flush_cqes(rtio_ctx);
	if (rc != 0) {
		rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
		rtio_iodev_sqe_err(parent_iodev_sqe, rc);
		return;
	}

	if (FIELD_GET(AKM09918C_ST1_DRDY, edata->reading.st1) == 0) {
		LOG_ERR("Data not ready, st1=0x%02x", edata->reading.st1);
		rtio_iodev_sqe_err(parent_iodev_sqe, -EBUSY);
		return;
	}
	rtio_iodev_sqe_ok(ctx->iodev_sqe, 0);

	edata->reading.data[0] = sys_le16_to_cpu(edata->reading.data[0]);
	edata->reading.data[1] = sys_le16_to_cpu(edata->reading.data[1]);
	edata->reading.data[2] = sys_le16_to_cpu(edata->reading.data[2]);

	rtio_iodev_sqe_ok(parent_iodev_sqe, 0);
}
+3 −3
Original line number Diff line number Diff line
@@ -70,9 +70,9 @@ static int akm09918c_decoder_decode(const uint8_t *buffer, struct sensor_chan_sp
		out->header.reading_count = 1;
		out->shift = AKM09918C_SHIFT;

		akm09918c_convert_raw_to_q31(edata->readings[0], &out->readings[0].x);
		akm09918c_convert_raw_to_q31(edata->readings[1], &out->readings[0].y);
		akm09918c_convert_raw_to_q31(edata->readings[2], &out->readings[0].z);
		akm09918c_convert_raw_to_q31(edata->reading.data[0], &out->readings[0].x);
		akm09918c_convert_raw_to_q31(edata->reading.data[1], &out->readings[0].y);
		akm09918c_convert_raw_to_q31(edata->reading.data[2], &out->readings[0].z);
		*fit = 1;

		return 1;