Skip to content

Commit 6b38cbe

Browse files
committed
rtio: add helper function rtio_read_transaction()
Add a helper function that constructs a rtio SQE chain with the purpose to perform a bus read operation on a list of registers. 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_transaction(dev, regs_list, ARRAY_SIZE(regs_list), BUS_SPI, rbuf, sqe, iodev, rtio, op_cb); Signed-off-by: Armando Visconti <armando.visconti@st.com>
1 parent f2c37c4 commit 6b38cbe

File tree

4 files changed

+215
-58
lines changed

4 files changed

+215
-58
lines changed

doc/releases/release-notes-4.2.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ New APIs and options
233233
* :kconfig:option:`CONFIG_ZPERF_SESSION_PER_THREAD`
234234
* :c:member:`zperf_upload_params.data_loader`
235235

236+
* RTIO
237+
238+
* :c:func:`rtio_is_spi`
239+
* :c:func:`rtio_is_cspi`
240+
* :c:func:`rtio_is_i3c`
241+
* :c:func:`rtio_read_regs_async`
242+
236243
* Sensor
237244

238245
* :c:func:`sensor_value_to_deci`

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <zephyr/sys/util.h>
1818
#include <stmemsc.h>
1919
#include "lsm6dsv16x_reg.h"
20+
#include <zephyr/rtio/regmap.h>
2021

2122
#define DT_DRV_COMPAT_LSM6DSV16X st_lsm6dsv16x
2223
#define DT_DRV_COMPAT_LSM6DSV32X st_lsm6dsv32x
@@ -171,9 +172,9 @@ struct lsm6dsv16x_data {
171172
uint16_t accel_batch_odr : 4;
172173
uint16_t gyro_batch_odr : 4;
173174
uint16_t temp_batch_odr : 2;
174-
uint16_t bus_type : 2; /* I2C is 0, SPI is 1, I3C is 2 */
175175
uint16_t sflp_batch_odr : 3;
176-
uint16_t reserved : 1;
176+
uint16_t reserved : 3;
177+
rtio_bus_type bus_type;
177178
int32_t gbias_x_udps;
178179
int32_t gbias_y_udps;
179180
int32_t gbias_z_udps;
@@ -206,13 +207,9 @@ struct lsm6dsv16x_data {
206207
};
207208

208209
#ifdef CONFIG_LSM6DSV16X_STREAM
209-
#define BUS_I2C 0
210-
#define BUS_SPI 1
211-
#define BUS_I3C 2
212-
213-
static inline uint8_t lsm6dsv16x_bus_reg(struct lsm6dsv16x_data *data, uint8_t x)
210+
static inline uint8_t lsm6dsv16x_bus_reg(rtio_bus_type bus, uint8_t addr)
214211
{
215-
return (data->bus_type == BUS_SPI) ? x | 0x80 : x;
212+
return (rtio_is_spi(bus)) ? addr | 0x80 : addr;
216213
}
217214

218215
#define LSM6DSV16X_FIFO_ITEM_LEN 7

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,6 @@
1616
#include <zephyr/logging/log.h>
1717
LOG_MODULE_DECLARE(LSM6DSV16X_RTIO);
1818

19-
/*
20-
* Create a chain of SQEs representing a bus transaction to read a reg.
21-
* The RTIO-enabled bus driver will:
22-
*
23-
* - write "reg" address
24-
* - read "len" data bytes into "buf".
25-
* - call complete_op callback
26-
*
27-
* If drdy_xl is active it reads XL data (6 bytes) from LSM6DSV16X_OUTX_L_A reg.
28-
*/
29-
static void lsm6dsv16x_rtio_rw_transaction(const struct device *dev, uint8_t reg,
30-
uint8_t *buf, uint32_t len,
31-
rtio_callback_t complete_op_cb)
32-
{
33-
struct lsm6dsv16x_data *lsm6dsv16x = dev->data;
34-
struct rtio *rtio = lsm6dsv16x->rtio_ctx;
35-
struct rtio_iodev *iodev = lsm6dsv16x->iodev;
36-
struct rtio_sqe *write_addr = rtio_sqe_acquire(rtio);
37-
struct rtio_sqe *read_reg = rtio_sqe_acquire(rtio);
38-
struct rtio_sqe *complete_op = rtio_sqe_acquire(rtio);
39-
struct rtio_iodev_sqe *sqe = lsm6dsv16x->streaming_sqe;
40-
uint8_t reg_bus = lsm6dsv16x_bus_reg(lsm6dsv16x, reg);
41-
42-
/* check we have been able to acquire sqe */
43-
if (write_addr == NULL || read_reg == NULL || complete_op == NULL) {
44-
return;
45-
}
46-
47-
rtio_sqe_prep_tiny_write(write_addr, iodev, RTIO_PRIO_NORM, &reg_bus, 1, NULL);
48-
write_addr->flags = RTIO_SQE_TRANSACTION;
49-
rtio_sqe_prep_read(read_reg, iodev, RTIO_PRIO_NORM, buf, len, NULL);
50-
read_reg->flags = RTIO_SQE_CHAINED;
51-
if (lsm6dsv16x->bus_type == BUS_I2C) {
52-
read_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
53-
} else if (lsm6dsv16x->bus_type == BUS_I3C) {
54-
read_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
55-
}
56-
57-
rtio_sqe_prep_callback_no_cqe(complete_op, complete_op_cb, (void *)dev, sqe);
58-
rtio_submit(rtio, 0);
59-
}
60-
6119
static void lsm6dsv16x_config_drdy(const struct device *dev, struct trigger_config trig_cfg)
6220
{
6321
const struct lsm6dsv16x_config *config = dev->config;
@@ -500,6 +458,10 @@ static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe,
500458
read_buf = buf + sizeof(hdr);
501459
buf_avail = buf_len - sizeof(hdr);
502460

461+
uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
462+
LSM6DSV16X_FIFO_DATA_OUT_TAG), };
463+
struct rtio_reg_buf rbuf[] = { {read_buf, buf_avail}, };
464+
503465
/*
504466
* Prepare rtio enabled bus to read all fifo_count entries from
505467
* LSM6DSV16X_FIFO_DATA_OUT_TAG. Then lsm6dsv16x_complete_op_cb
@@ -515,8 +477,15 @@ static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe,
515477
* lsm6dsv16x_fifo_out_raw_get(&dev_ctx, &f_data);
516478
* }
517479
*/
518-
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_FIFO_DATA_OUT_TAG,
519-
read_buf, buf_avail, lsm6dsv16x_complete_op_cb);
480+
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
481+
lsm6dsv16x->iodev,
482+
fifo_regs,
483+
ARRAY_SIZE(fifo_regs),
484+
lsm6dsv16x->bus_type,
485+
rbuf,
486+
lsm6dsv16x->streaming_sqe,
487+
dev,
488+
lsm6dsv16x_complete_op_cb);
520489
}
521490

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

615+
uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
616+
LSM6DSV16X_OUTX_L_A), };
617+
struct rtio_reg_buf rbuf[] = { {read_buf, 6}, };
618+
646619
/*
647620
* Prepare rtio enabled bus to read LSM6DSV16X_OUTX_L_A register
648621
* where accelerometer data is available.
@@ -654,8 +627,15 @@ static void lsm6dsv16x_read_status_cb(struct rtio *r, const struct rtio_sqe *sqe
654627
*
655628
* lsm6dsv16x_acceleration_raw_get(&dev_ctx, accel_raw);
656629
*/
657-
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_OUTX_L_A,
658-
read_buf, 6, lsm6dsv16x_complete_op_cb);
630+
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
631+
lsm6dsv16x->iodev,
632+
fifo_regs,
633+
ARRAY_SIZE(fifo_regs),
634+
lsm6dsv16x->bus_type,
635+
rbuf,
636+
lsm6dsv16x->streaming_sqe,
637+
dev,
638+
lsm6dsv16x_complete_op_cb);
659639
}
660640
}
661641

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

694+
uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
695+
LSM6DSV16X_FIFO_STATUS1), };
696+
struct rtio_reg_buf rbuf[] = { {lsm6dsv16x->fifo_status, 2}, };
697+
714698
/*
715699
* Prepare rtio enabled bus to read LSM6DSV16X_FIFO_STATUS1 and
716700
* LSM6DSV16X_FIFO_STATUS2 registers where FIFO threshold condition and
@@ -723,8 +707,16 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
723707
*
724708
* lsm6dsv16x_fifo_status_get(&dev_ctx, &fifo_status);
725709
*/
726-
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_FIFO_STATUS1,
727-
lsm6dsv16x->fifo_status, 2, lsm6dsv16x_read_fifo_cb);
710+
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
711+
lsm6dsv16x->iodev,
712+
fifo_regs,
713+
ARRAY_SIZE(fifo_regs),
714+
lsm6dsv16x->bus_type,
715+
rbuf,
716+
lsm6dsv16x->streaming_sqe,
717+
dev,
718+
lsm6dsv16x_read_fifo_cb);
719+
728720
#if LSM6DSVXXX_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
729721
}
730722
#endif
@@ -734,6 +726,10 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
734726
if (lsm6dsv16x->trig_cfg.int_drdy) {
735727
lsm6dsv16x->status = 0;
736728

729+
uint8_t fifo_regs[] = { lsm6dsv16x_bus_reg(lsm6dsv16x->bus_type,
730+
LSM6DSV16X_STATUS_REG), };
731+
struct rtio_reg_buf rbuf[] = { {&lsm6dsv16x->status, 1}, };
732+
737733
/*
738734
* Prepare rtio enabled bus to read LSM6DSV16X_STATUS_REG register
739735
* where accelerometer and gyroscope data ready status is available.
@@ -745,7 +741,14 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev)
745741
*
746742
* lsm6dsv16x_flag_data_ready_get(&dev_ctx, &drdy);
747743
*/
748-
lsm6dsv16x_rtio_rw_transaction(dev, LSM6DSV16X_STATUS_REG,
749-
&lsm6dsv16x->status, 1, lsm6dsv16x_read_status_cb);
744+
rtio_read_regs_async(lsm6dsv16x->rtio_ctx,
745+
lsm6dsv16x->iodev,
746+
fifo_regs,
747+
ARRAY_SIZE(fifo_regs),
748+
lsm6dsv16x->bus_type,
749+
rbuf,
750+
lsm6dsv16x->streaming_sqe,
751+
dev,
752+
lsm6dsv16x_read_status_cb);
750753
}
751754
}

include/zephyr/rtio/regmap.h

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2025 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_RTIO_REGMAP_H_
8+
#define ZEPHYR_INCLUDE_RTIO_REGMAP_H_
9+
10+
#include <zephyr/rtio/rtio.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief A structure to describe a list of not-consecutive memory chunks
18+
* for RTIO operations.
19+
*/
20+
struct rtio_reg_buf {
21+
/* Valid pointer to a data buffer */
22+
uint8_t *bufp;
23+
24+
/* Length of the buffer in bytes */
25+
size_t len;
26+
};
27+
28+
/**
29+
* @brief bus type
30+
*
31+
* RTIO works on top of a RTIO enabled bus, Some RTIO ops require
32+
* a bus-related handling (e.g. rtio_read_regs_async)
33+
*/
34+
typedef enum {
35+
BUS_I2C,
36+
BUS_SPI,
37+
BUS_I3C,
38+
} rtio_bus_type;
39+
40+
/**
41+
* @brief chceck if bus is SPI
42+
*/
43+
static inline bool rtio_is_spi(rtio_bus_type bus_type)
44+
{
45+
return (bus_type == BUS_SPI);
46+
}
47+
48+
/**
49+
* @brief chceck if bus is I2C
50+
*/
51+
static inline bool rtio_is_i2c(rtio_bus_type bus_type)
52+
{
53+
return (bus_type == BUS_I2C);
54+
}
55+
56+
/**
57+
* @brief chceck if bus is I3C
58+
*/
59+
static inline bool rtio_is_i3c(rtio_bus_type bus_type)
60+
{
61+
return (bus_type == BUS_I3C);
62+
}
63+
64+
/*
65+
* @brief Create a chain of SQEs representing a bus transaction to read a reg.
66+
*
67+
* The RTIO-enabled bus driver is isnstrumented to perform bus read ops
68+
* for each register in the list.
69+
*
70+
* Usage:
71+
*
72+
* uint8_t regs_list[] = { reg_addr1, reg_addr2. ... }
73+
* struct rtio_reg_buf rbuf[] = {{mem_addr_1, mem_len_1},
74+
* {mem_addr_2, mem_len_2},
75+
* ...
76+
* };
77+
*
78+
* rtio_read_regs_async(dev,
79+
* regs_list,
80+
* ARRAY_SIZE(regs_list),
81+
* BUS_SPI,
82+
* rbuf,
83+
* sqe,
84+
* iodev,
85+
* rtio,
86+
* op_cb);
87+
*
88+
* @param regs pointer to list of registers to be read. Raise proper bit in case of SPI bus
89+
* @param rtio_bus_type bus type (i2c, spi, i3c)
90+
* @param rtio_reg_buf buffer of memory chunks
91+
* @param iodev_sqe IODEV submission for the await op
92+
* @param iodev IO device
93+
* @param r RTIO context
94+
* @param rtio_callback_t callback routine at the end of op
95+
*/
96+
static inline void rtio_read_regs_async(struct rtio *r,
97+
struct rtio_iodev *iodev,
98+
uint8_t *regs,
99+
uint8_t regs_num,
100+
rtio_bus_type bus_type,
101+
struct rtio_reg_buf *buf,
102+
struct rtio_iodev_sqe *iodev_sqe,
103+
const struct device *dev,
104+
rtio_callback_t complete_op_cb)
105+
{
106+
struct rtio_sqe *write_addr;
107+
struct rtio_sqe *read_reg;
108+
struct rtio_sqe *complete_op;
109+
uint8_t i;
110+
111+
for (i = 0; i < regs_num; i++) {
112+
113+
write_addr = rtio_sqe_acquire(r);
114+
read_reg = rtio_sqe_acquire(r);
115+
116+
if (write_addr == NULL || read_reg == NULL) {
117+
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
118+
rtio_sqe_drop_all(r);
119+
return;
120+
}
121+
122+
rtio_sqe_prep_tiny_write(write_addr, iodev, RTIO_PRIO_NORM, &regs[i], 1, NULL);
123+
write_addr->flags = RTIO_SQE_TRANSACTION;
124+
rtio_sqe_prep_read(read_reg, iodev, RTIO_PRIO_NORM, buf[i].bufp, buf[i].len, NULL);
125+
read_reg->flags = RTIO_SQE_CHAINED;
126+
127+
if (rtio_is_i2c(bus_type)) {
128+
read_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
129+
} else if (rtio_is_i3c(bus_type)) {
130+
read_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
131+
}
132+
}
133+
134+
complete_op = rtio_sqe_acquire(r);
135+
if (complete_op == NULL) {
136+
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
137+
rtio_sqe_drop_all(r);
138+
return;
139+
}
140+
141+
rtio_sqe_prep_callback_no_cqe(complete_op, complete_op_cb, (void *)dev, iodev_sqe);
142+
143+
rtio_submit(r, 0);
144+
}
145+
146+
#ifdef __cplusplus
147+
}
148+
#endif
149+
150+
#endif /* ZEPHYR_INCLUDE_RTIO_REGMAP_H_ */

0 commit comments

Comments
 (0)