-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
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
There are no files selected for viewing
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) { | ||
|
@@ -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; | ||
} | ||
|
@@ -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; | ||
} | ||
|
||
|
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); | ||
|
||
|
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 | ||
*/ | ||
|
||
|
@@ -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 GitHub Actions / Run compliance checks on patch series (PR)SPACING
|
||
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 GitHub Actions / Run compliance checks on patch series (PR)TYPO_SPELLING
|
||
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); | ||
}else{ | ||
Check failure on line 68 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c GitHub Actions / Run compliance checks on patch series (PR)SPACING
|
||
rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync); | ||
Check notice on line 69 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
} | ||
} | ||
|
||
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); | ||
} | ||
Check warning on line 101 in drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c GitHub Actions / Run compliance checks on patch series (PR)MISSING_EOF_NEWLINE
|