-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: sensor: akm09918: make submit function more unblocking
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
1 parent
3b6555a
commit 1a89d4b
Showing
3 changed files
with
109 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ | ||
|
||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) | ||
|
@@ -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; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ | ||
|
||
|
@@ -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 { | ||
|
@@ -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); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ | ||
|
@@ -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) | ||
|
@@ -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); | ||
} |