Skip to content

Commit

Permalink
drivers: sensor: akm09918: make submit function more unblocking
Browse files Browse the repository at this point in the history
The driver now does not wait for the completion of a measurement
in the submit function.
Instead it schedule the fetch and the completion of the
submission queue entry as delayed work to the system work queue.

Signed-off-by: Florian Weber <[email protected]>
  • Loading branch information
FlorianWeber1018 authored and MaureenHelm committed Oct 23, 2024
1 parent 3b6555a commit 1a89d4b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 35 deletions.
50 changes: 35 additions & 15 deletions drivers/sensor/asahi_kasei/akm09918c/akm09918c.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023 Google LLC
* Copyright (c) 2024 Florian Weber <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -21,21 +22,16 @@
LOG_MODULE_REGISTER(AKM09918C, CONFIG_SENSOR_LOG_LEVEL);

/**
* @brief Perform the bus transaction to fetch samples
* @brief Perform the bus transaction to start measurement.
*
* @param dev Sensor device to operate on
* @param chan Channel ID to fetch
* @param x Location to write X channel sample.
* @param y Location to write Y channel sample.
* @param z Location to write Z channel sample.
* @param chan Channel ID for starting the measurement
* @return int 0 if successful or error code
*/
int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel chan, int16_t *x,
int16_t *y, int16_t *z)
int akm09918c_start_measurement(const struct device *dev, enum sensor_channel chan)
{
struct akm09918c_data *data = dev->data;
const struct akm09918c_config *cfg = dev->config;
uint8_t buf[9] = {0};

if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_MAGN_X && chan != SENSOR_CHAN_MAGN_Y &&
chan != SENSOR_CHAN_MAGN_Z && chan != SENSOR_CHAN_MAGN_XYZ) {
Expand All @@ -49,11 +45,24 @@ int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel
LOG_ERR("Failed to start measurement.");
return -EIO;
}

/* Wait for sample */
LOG_DBG("Waiting for sample...");
k_usleep(AKM09918C_MEASURE_TIME_US);
}
return 0;
}

/**
* @brief Perform the bus transaction to fetch samples.
*
* @param dev Sensor device to operate on
* @param chan Channel ID to fetch
* @param x Location to write X channel sample.
* @param y Location to write Y channel sample.
* @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)
{
const struct akm09918c_config *cfg = dev->config;
uint8_t buf[9] = {0};

/* We have to read through the TMPS register or the data_ready bit won't clear */
if (i2c_burst_read_dt(&cfg->i2c, AKM09918C_REG_ST1, buf, ARRAY_SIZE(buf)) != 0) {
Expand All @@ -77,8 +86,16 @@ static int akm09918c_sample_fetch(const struct device *dev, enum sensor_channel
{
struct akm09918c_data *data = dev->data;

return akm09918c_sample_fetch_helper(dev, chan, &data->x_sample, &data->y_sample,
&data->z_sample);
int ret = akm09918c_start_measurement(dev, chan);

if (ret) {
return ret;
}
/* Wait for sample */
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);
}

static void akm09918c_convert(struct sensor_value *val, int16_t sample)
Expand Down Expand Up @@ -213,7 +230,10 @@ static int akm09918c_init(const struct device *dev)
return rc;
}
data->mode = AKM09918C_CNTL2_PWR_DOWN;

#ifdef CONFIG_SENSOR_ASYNC_API
/* init work for fetching after measurement has completed */
k_work_init_delayable(&data->work_ctx.async_fetch_work, akm09918_async_fetch);
#endif
return 0;
}

Expand Down
15 changes: 12 additions & 3 deletions drivers/sensor/asahi_kasei/akm09918c/akm09918c.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023 Google LLC
* Copyright (c) 2024 Florian Weber <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -34,6 +35,13 @@ struct akm09918c_data {
int16_t y_sample;
int16_t z_sample;
uint8_t mode;
#ifdef CONFIG_SENSOR_ASYNC_API
struct akm09918c_async_fetch_ctx {
struct rtio_iodev_sqe *iodev_sqe;
uint64_t timestamp;
struct k_work_delayable async_fetch_work;
} work_ctx;
#endif
};

struct akm09918c_config {
Expand Down Expand Up @@ -74,22 +82,23 @@ 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_fetch_measurement(const struct device *dev, int16_t *x, int16_t *y, int16_t *z);
/*
* RTIO types
*/

struct akm09918c_decoder_header {
uint64_t timestamp;
} __attribute__((__packed__));
} __packed;

struct akm09918c_encoded_data {
struct akm09918c_decoder_header header;
int16_t readings[3];
};

int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel chan, int16_t *x,
int16_t *y, int16_t *z);
void akm09918_async_fetch(struct k_work *work);

int akm09918c_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder);

Expand Down
79 changes: 62 additions & 17 deletions drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2023 Google LLC
* Copyright (c) 2024 Croxel Inc.
* Copyright (c) 2024 Florian Weber <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -16,32 +17,46 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
{
const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
const struct device *dev = cfg->sensor;
uint32_t min_buf_len = sizeof(struct akm09918c_encoded_data);
struct akm09918c_data *data = dev->data;
const struct sensor_chan_spec *const channels = cfg->channels;
const size_t num_channels = cfg->count;
int rc;
uint8_t *buf;
uint32_t buf_len;
struct akm09918c_encoded_data *edata;

/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len);
if (rc != 0) {
LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len);
rtio_iodev_sqe_err(iodev_sqe, rc);
return;
/* Check if the requested channels are supported */
for (size_t i = 0; i < num_channels; i++) {
switch (channels[i].chan_type) {
case SENSOR_CHAN_MAGN_X:
case SENSOR_CHAN_MAGN_Y:
case SENSOR_CHAN_MAGN_Z:
case SENSOR_CHAN_MAGN_XYZ:
case SENSOR_CHAN_ALL:
break;
default:
LOG_ERR("Unsupported channel type %d", channels[i].chan_type);
rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
return;
}
}

edata = (struct akm09918c_encoded_data *)buf;
edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());

rc = akm09918c_sample_fetch_helper(dev, SENSOR_CHAN_MAGN_XYZ, &edata->readings[0],
&edata->readings[1], &edata->readings[2]);
/* start the measurement in the sensor */
rc = akm09918c_start_measurement(dev, SENSOR_CHAN_MAGN_XYZ);
if (rc != 0) {
LOG_ERR("Failed to fetch samples");
LOG_ERR("Failed to fetch samples.");
rtio_iodev_sqe_err(iodev_sqe, rc);
return;
}

rtio_iodev_sqe_ok(iodev_sqe, 0);
/* save information for the work item */
data->work_ctx.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
data->work_ctx.iodev_sqe = iodev_sqe;

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. "
"Try again later when the last sensor read operation has finished.");
rtio_iodev_sqe_err(iodev_sqe, -EBUSY);
}
return;
}

void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
Expand All @@ -57,3 +72,33 @@ void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe

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);
struct akm09918c_async_fetch_ctx *ctx =
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;
uint32_t req_buf_len = sizeof(struct akm09918c_encoded_data);
uint32_t buf_len;
uint8_t *buf;
struct akm09918c_encoded_data *edata;
int rc;

/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
rc = rtio_sqe_rx_buf(ctx->iodev_sqe, req_buf_len, req_buf_len, &buf, &buf_len);
if (rc != 0) {
LOG_ERR("Failed to get a read buffer of size %u bytes", req_buf_len);
rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
return;
}
edata = (struct akm09918c_encoded_data *)buf;
rc = akm09918c_fetch_measurement(dev, &edata->readings[0], &edata->readings[1],
&edata->readings[2]);
if (rc != 0) {
rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
return;
}
rtio_iodev_sqe_ok(ctx->iodev_sqe, 0);
}

0 comments on commit 1a89d4b

Please sign in to comment.