Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: sensors: akm09918: make submit function more unblocking #74389

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
Loading