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 committed Oct 14, 2024
1 parent 27456ed commit 40174cc
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 42 deletions.
56 changes: 38 additions & 18 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 @@ -66,9 +75,9 @@ int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel
return -EBUSY;
}

*x = sys_le16_to_cpu(buf[1] | (buf[2] << 8));
*y = sys_le16_to_cpu(buf[3] | (buf[4] << 8));
*z = sys_le16_to_cpu(buf[5] | (buf[6] << 8));
*x = buf[1] | (buf[2] << 8);
*y = buf[3] | (buf[4] << 8);
*z = buf[5] | (buf[6] << 8);

return 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
89 changes: 68 additions & 21 deletions drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c
Original file line number Diff line number Diff line change
@@ -1,7 +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,39 +16,86 @@ 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)
{
struct rtio_work_req *req = rtio_work_req_alloc();

__ASSERT_NO_MSG(req);

rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync);
if(!req){

Check failure on line 65 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:65 space required before the open brace '{'

Check failure on line 65 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:65 space required before the open parenthesis '('
LOG_ERR("RTIO work item allocation failed. Consider to to increase CONFIG_RTIO_WORKQ_POOL_ITEMS.");

Check warning on line 66 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

TYPO_SPELLING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:66 'to to' may be misspelled - perhaps 'to'?

Check warning on line 66 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE_STRING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:66 line length of 115 exceeds 100 columns
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
}else{

Check failure on line 68 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:68 space required before the open brace '{'

Check failure on line 68 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:68 space required after that close brace '}'
rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync);

Check notice on line 69 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:69 - if(!req){ - LOG_ERR("RTIO work item allocation failed. Consider to to increase CONFIG_RTIO_WORKQ_POOL_ITEMS."); + if (!req) { + LOG_ERR("RTIO work item allocation failed. Consider to to increase " + "CONFIG_RTIO_WORKQ_POOL_ITEMS."); rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); - }else{ + } else {
}
}

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;

Check failure on line 85 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

TRAILING_WHITESPACE

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:85 trailing whitespace
/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */

Check notice on line 86 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:86 - +
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);
}

Check warning on line 101 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

MISSING_EOF_NEWLINE

drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c:101 adding a line without newline at end of file

0 comments on commit 40174cc

Please sign in to comment.