Skip to content

rtio: add helper function rtio_read_transaction() #91775

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions doc/releases/release-notes-4.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ New APIs and options
* :kconfig:option:`CONFIG_ZPERF_SESSION_PER_THREAD`
* :c:member:`zperf_upload_params.data_loader`

* RTIO

* :c:func:`rtio_is_spi`
* :c:func:`rtio_is_cspi`
* :c:func:`rtio_is_i3c`
* :c:func:`rtio_read_regs_async`

* Sensor

* :c:func:`sensor_value_to_deci`
Expand Down
13 changes: 5 additions & 8 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <zephyr/sys/util.h>
#include <stmemsc.h>
#include "lsm6dsv16x_reg.h"
#include <zephyr/rtio/regmap.h>

#define DT_DRV_COMPAT_LSM6DSV16X st_lsm6dsv16x
#define DT_DRV_COMPAT_LSM6DSV32X st_lsm6dsv32x
Expand Down Expand Up @@ -171,9 +172,9 @@ struct lsm6dsv16x_data {
uint16_t accel_batch_odr : 4;
uint16_t gyro_batch_odr : 4;
uint16_t temp_batch_odr : 2;
uint16_t bus_type : 2; /* I2C is 0, SPI is 1, I3C is 2 */
uint16_t sflp_batch_odr : 3;
uint16_t reserved : 1;
uint16_t reserved : 3;
rtio_bus_type bus_type;
int32_t gbias_x_udps;
int32_t gbias_y_udps;
int32_t gbias_z_udps;
Expand Down Expand Up @@ -206,13 +207,9 @@ struct lsm6dsv16x_data {
};

#ifdef CONFIG_LSM6DSV16X_STREAM
#define BUS_I2C 0
#define BUS_SPI 1
#define BUS_I3C 2

static inline uint8_t lsm6dsv16x_bus_reg(struct lsm6dsv16x_data *data, uint8_t x)
static inline uint8_t lsm6dsv16x_bus_reg(rtio_bus_type bus, uint8_t addr)
{
return (data->bus_type == BUS_SPI) ? x | 0x80 : x;
return (rtio_is_spi(bus)) ? addr | 0x80 : addr;
}

#define LSM6DSV16X_FIFO_ITEM_LEN 7
Expand Down
103 changes: 53 additions & 50 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,6 @@
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(LSM6DSV16X_RTIO);

/*
* Create a chain of SQEs representing a bus transaction to read a reg.
* The RTIO-enabled bus driver will:
*
* - write "reg" address
* - read "len" data bytes into "buf".
* - call complete_op callback
*
* If drdy_xl is active it reads XL data (6 bytes) from LSM6DSV16X_OUTX_L_A reg.
*/
static void lsm6dsv16x_rtio_rw_transaction(const struct device *dev, uint8_t reg,
uint8_t *buf, uint32_t len,
rtio_callback_t complete_op_cb)
{
struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
struct rtio *rtio = lsm6dsv16x->rtio_ctx;
struct rtio_iodev *iodev = lsm6dsv16x->iodev;
struct rtio_sqe *write_addr = rtio_sqe_acquire(rtio);
struct rtio_sqe *read_reg = rtio_sqe_acquire(rtio);
struct rtio_sqe *complete_op = rtio_sqe_acquire(rtio);
struct rtio_iodev_sqe *sqe = lsm6dsv16x->streaming_sqe;
uint8_t reg_bus = lsm6dsv16x_bus_reg(lsm6dsv16x, reg);

/* check we have been able to acquire sqe */
if (write_addr == NULL || read_reg == NULL || complete_op == NULL) {
return;
}

rtio_sqe_prep_tiny_write(write_addr, iodev, RTIO_PRIO_NORM, &reg_bus, 1, NULL);
write_addr->flags = RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_reg, iodev, RTIO_PRIO_NORM, buf, len, NULL);
read_reg->flags = RTIO_SQE_CHAINED;
if (lsm6dsv16x->bus_type == BUS_I2C) {
read_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
} else if (lsm6dsv16x->bus_type == BUS_I3C) {
read_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
}

rtio_sqe_prep_callback_no_cqe(complete_op, complete_op_cb, (void *)dev, sqe);
rtio_submit(rtio, 0);
}

static void lsm6dsv16x_config_drdy(const struct device *dev, struct trigger_config trig_cfg)
{
const struct lsm6dsv16x_config *config = dev->config;
Expand Down Expand Up @@ -500,6 +458,10 @@ static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe,
read_buf = buf + sizeof(hdr);
buf_avail = buf_len - sizeof(hdr);

uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
LSM6DSV16X_FIFO_DATA_OUT_TAG), };
struct rtio_reg_buf rbuf[] = { {read_buf, buf_avail}, };

/*
* Prepare rtio enabled bus to read all fifo_count entries from
* LSM6DSV16X_FIFO_DATA_OUT_TAG. Then lsm6dsv16x_complete_op_cb
Expand All @@ -515,8 +477,15 @@ static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe,
* lsm6dsv16x_fifo_out_raw_get(&dev_ctx, &f_data);
* }
*/
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_FIFO_DATA_OUT_TAG,
read_buf, buf_avail, lsm6dsv16x_complete_op_cb);
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
lsm6dsv16x->iodev,
fifo_regs,
ARRAY_SIZE(fifo_regs),
lsm6dsv16x->bus_type,
rbuf,
lsm6dsv16x->streaming_sqe,
dev,
lsm6dsv16x_complete_op_cb);
}

/*
Expand Down Expand Up @@ -643,6 +612,10 @@ static void lsm6dsv16x_read_status_cb(struct rtio *r, const struct rtio_sqe *sqe
memcpy(buf, &hdr, sizeof(hdr));
read_buf = (uint8_t *)&((struct lsm6dsv16x_rtio_data *)buf)->acc[0];

uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
LSM6DSV16X_OUTX_L_A), };
struct rtio_reg_buf rbuf[] = { {read_buf, 6}, };

/*
* Prepare rtio enabled bus to read LSM6DSV16X_OUTX_L_A register
* where accelerometer data is available.
Expand All @@ -654,8 +627,15 @@ static void lsm6dsv16x_read_status_cb(struct rtio *r, const struct rtio_sqe *sqe
*
* lsm6dsv16x_acceleration_raw_get(&dev_ctx, accel_raw);
*/
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_OUTX_L_A,
read_buf, 6, lsm6dsv16x_complete_op_cb);
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
lsm6dsv16x->iodev,
fifo_regs,
ARRAY_SIZE(fifo_regs),
lsm6dsv16x->bus_type,
rbuf,
lsm6dsv16x->streaming_sqe,
dev,
lsm6dsv16x_complete_op_cb);
}
}

Expand Down Expand Up @@ -711,6 +691,10 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
#endif
lsm6dsv16x->fifo_status[0] = lsm6dsv16x->fifo_status[1] = 0;

uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
LSM6DSV16X_FIFO_STATUS1), };
struct rtio_reg_buf rbuf[] = { {lsm6dsv16x->fifo_status, 2}, };

/*
* Prepare rtio enabled bus to read LSM6DSV16X_FIFO_STATUS1 and
* LSM6DSV16X_FIFO_STATUS2 registers where FIFO threshold condition and
Expand All @@ -723,8 +707,16 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
*
* lsm6dsv16x_fifo_status_get(&dev_ctx, &fifo_status);
*/
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_FIFO_STATUS1,
lsm6dsv16x->fifo_status, 2, lsm6dsv16x_read_fifo_cb);
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
lsm6dsv16x->iodev,
fifo_regs,
ARRAY_SIZE(fifo_regs),
lsm6dsv16x->bus_type,
rbuf,
lsm6dsv16x->streaming_sqe,
dev,
lsm6dsv16x_read_fifo_cb);

#if LSM6DSVXXX_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
}
#endif
Expand All @@ -734,6 +726,10 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
if (lsm6dsv16x->trig_cfg.int_drdy) {
lsm6dsv16x->status = 0;

uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
LSM6DSV16X_STATUS_REG), };
struct rtio_reg_buf rbuf[] = { {&lsm6dsv16x->status, 1}, };

/*
* Prepare rtio enabled bus to read LSM6DSV16X_STATUS_REG register
* where accelerometer and gyroscope data ready status is available.
Expand All @@ -745,7 +741,14 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
*
* lsm6dsv16x_flag_data_ready_get(&dev_ctx, &drdy);
*/
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_STATUS_REG,
&lsm6dsv16x->status, 1, lsm6dsv16x_read_status_cb);
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
lsm6dsv16x->iodev,
fifo_regs,
ARRAY_SIZE(fifo_regs),
lsm6dsv16x->bus_type,
rbuf,
lsm6dsv16x->streaming_sqe,
dev,
lsm6dsv16x_read_status_cb);
}
}
150 changes: 150 additions & 0 deletions include/zephyr/rtio/regmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2025 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_RTIO_REGMAP_H_
#define ZEPHYR_INCLUDE_RTIO_REGMAP_H_

#include <zephyr/rtio/rtio.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief A structure to describe a list of not-consecutive memory chunks
* for RTIO operations.
*/
struct rtio_reg_buf {
/* Valid pointer to a data buffer */
uint8_t *bufp;

/* Length of the buffer in bytes */
size_t len;
};

/**
* @brief bus type
*
* RTIO works on top of a RTIO enabled bus, Some RTIO ops require
* a bus-related handling (e.g. rtio_read_regs_async)
*/
typedef enum {
BUS_I2C,
BUS_SPI,
BUS_I3C,
} rtio_bus_type;

/**
* @brief chceck if bus is SPI
*/
static inline bool rtio_is_spi(rtio_bus_type bus_type)
{
return (bus_type == BUS_SPI);
}

/**
* @brief chceck if bus is I2C
*/
static inline bool rtio_is_i2c(rtio_bus_type bus_type)
{
return (bus_type == BUS_I2C);
}

/**
* @brief chceck if bus is I3C
*/
static inline bool rtio_is_i3c(rtio_bus_type bus_type)
{
return (bus_type == BUS_I3C);
}

/*
* @brief Create a chain of SQEs representing a bus transaction to read a reg.
*
* The RTIO-enabled bus driver is isnstrumented to perform bus read ops
* for each register in the list.
*
* Usage:
*
* uint8_t regs_list[] = { reg_addr1, reg_addr2. ... }
* struct rtio_reg_buf rbuf[] = {{mem_addr_1, mem_len_1},
* {mem_addr_2, mem_len_2},
* ...
* };
*
* rtio_read_regs_async(dev,
* regs_list,
* ARRAY_SIZE(regs_list),
* BUS_SPI,
* rbuf,
* sqe,
* iodev,
* rtio,
* op_cb);
*
* @param regs pointer to list of registers to be read. Raise proper bit in case of SPI bus
* @param rtio_bus_type bus type (i2c, spi, i3c)
* @param rtio_reg_buf buffer of memory chunks
* @param iodev_sqe IODEV submission for the await op
* @param iodev IO device
* @param r RTIO context
* @param rtio_callback_t callback routine at the end of op
*/
static inline void rtio_read_regs_async(struct rtio *r,
struct rtio_iodev *iodev,
uint8_t *regs,
uint8_t regs_num,
rtio_bus_type bus_type,
struct rtio_reg_buf *buf,
struct rtio_iodev_sqe *iodev_sqe,
const struct device *dev,
rtio_callback_t complete_op_cb)
{
struct rtio_sqe *write_addr;
struct rtio_sqe *read_reg;
struct rtio_sqe *complete_op;
uint8_t i;

for (i = 0; i < regs_num; i++) {

write_addr = rtio_sqe_acquire(r);
read_reg = rtio_sqe_acquire(r);

if (write_addr == NULL || read_reg == NULL) {
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
rtio_sqe_drop_all(r);
return;
}

rtio_sqe_prep_tiny_write(write_addr, iodev, RTIO_PRIO_NORM, &regs[i], 1, NULL);
write_addr->flags = RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_reg, iodev, RTIO_PRIO_NORM, buf[i].bufp, buf[i].len, NULL);
read_reg->flags = RTIO_SQE_CHAINED;

if (rtio_is_i2c(bus_type)) {
read_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
} else if (rtio_is_i3c(bus_type)) {
read_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
}
}

complete_op = rtio_sqe_acquire(r);
if (complete_op == NULL) {
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
rtio_sqe_drop_all(r);
return;
}

rtio_sqe_prep_callback_no_cqe(complete_op, complete_op_cb, (void *)dev, iodev_sqe);

rtio_submit(r, 0);
}

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_RTIO_REGMAP_H_ */