diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c.c b/drivers/sensor/asahi_kasei/akm09918c/akm09918c.c index 50664bcdbc5ad9f..ecc04943aa9b7e2 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c.c +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c.c @@ -21,21 +21,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 +44,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 +74,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 +85,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 +229,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; } diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c.h b/drivers/sensor/asahi_kasei/akm09918c/akm09918c.h index a4b35c64dd83872..84d99d51320bb67 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c.h +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c.h @@ -34,6 +34,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,7 +81,9 @@ 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 */ @@ -88,8 +97,7 @@ struct akm09918c_encoded_data { 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); diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c index 6fb5d901ec4d067..8758eb8663b50e5 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c @@ -9,32 +9,58 @@ LOG_MODULE_DECLARE(AKM09918C, CONFIG_SENSOR_LOG_LEVEL); -void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +void akm09918_async_fetch(struct k_work *work) { - uint32_t min_buf_len = sizeof(struct akm09918c_encoded_data); - int rc; - uint8_t *buf; + 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(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len); + 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", min_buf_len); - rtio_iodev_sqe_err(iodev_sqe, rc); + 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; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + 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); +} + +void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + int rc; + struct akm09918c_data *data = dev->data; - 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; }