Skip to content

Commit 9d5201f

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 9d5201f

File tree

4 files changed

+231
-58
lines changed

4 files changed

+231
-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: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
* return true if bus is SPI
44+
*
45+
* @param rtio_bus_type bus type (i2c, spi, i3c)
46+
*/
47+
static inline bool rtio_is_spi(rtio_bus_type bus_type)
48+
{
49+
return (bus_type == BUS_SPI);
50+
}
51+
52+
/**
53+
* @brief chceck if bus is I2C
54+
*
55+
* return true if bus is I2C
56+
*
57+
* @param rtio_bus_type bus type (i2c, spi, i3c)
58+
*/
59+
static inline bool rtio_is_i2c(rtio_bus_type bus_type)
60+
{
61+
return (bus_type == BUS_I2C);
62+
}
63+
64+
/**
65+
* @brief chceck if bus is I3C
66+
*
67+
* return true if bus is I3C
68+
*
69+
* @param rtio_bus_type bus type (i2c, spi, i3c)
70+
*/
71+
static inline bool rtio_is_i3c(rtio_bus_type bus_type)
72+
{
73+
return (bus_type == BUS_I3C);
74+
}
75+
76+
/*
77+
* @brief Create a chain of SQEs representing a bus transaction to read a reg.
78+
*
79+
* The RTIO-enabled bus driver is isnstrumented to perform bus read ops
80+
* for each register in the list.
81+
*
82+
* Usage:
83+
*
84+
* uint8_t regs_list[] = { reg_addr1, reg_addr2. ... }
85+
* struct rtio_reg_buf rbuf[] = {{mem_addr_1, mem_len_1},
86+
* {mem_addr_2, mem_len_2},
87+
* ...
88+
* };
89+
*
90+
* rtio_read_regs_async(dev,
91+
* regs_list,
92+
* ARRAY_SIZE(regs_list),
93+
* BUS_SPI,
94+
* rbuf,
95+
* sqe,
96+
* iodev,
97+
* rtio,
98+
* op_cb);
99+
*
100+
* @param regs pointer to list of registers to be read. Raise proper bit in case of SPI bus
101+
* @param rtio_bus_type bus type (i2c, spi, i3c)
102+
* @param rtio_reg_buf buffer of memory chunks
103+
* @param iodev_sqe IODEV submission for the await op
104+
* @param iodev IO device
105+
* @param r RTIO context
106+
* @param rtio_callback_t callback routine at the end of op
107+
*/
108+
static inline void rtio_read_regs_async(struct rtio *r,
109+
struct rtio_iodev *iodev,
110+
uint8_t *regs,
111+
uint8_t regs_num,
112+
rtio_bus_type bus_type,
113+
struct rtio_reg_buf *buf,
114+
struct rtio_iodev_sqe *iodev_sqe,
115+
const struct device *dev,
116+
rtio_callback_t complete_op_cb)
117+
{
118+
struct rtio_sqe *write_addr;
119+
struct rtio_sqe *read_reg;
120+
struct rtio_sqe *complete_op;
121+
uint8_t i;
122+
123+
for (i = 0; i < regs_num; i++) {
124+
125+
write_addr = rtio_sqe_acquire(r);
126+
read_reg = rtio_sqe_acquire(r);
127+
128+
if (write_addr == NULL || read_reg == NULL) {
129+
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
130+
rtio_sqe_drop_all(r);
131+
return;
132+
}
133+
134+
rtio_sqe_prep_tiny_write(write_addr, iodev, RTIO_PRIO_NORM, &regs[i], 1, NULL);
135+
write_addr->flags = RTIO_SQE_TRANSACTION;
136+
rtio_sqe_prep_read(read_reg, iodev, RTIO_PRIO_NORM, buf[i].bufp, buf[i].len, NULL);
137+
read_reg->flags = RTIO_SQE_CHAINED;
138+
139+
if (rtio_is_i2c(bus_type)) {
140+
read_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
141+
} else if (rtio_is_i3c(bus_type)) {
142+
read_reg->iodev_flags |= RTIO_IODEV_I3C_STOP | RTIO_IODEV_I3C_RESTART;
143+
}
144+
}
145+
146+
complete_op = rtio_sqe_acquire(r);
147+
if (complete_op == NULL) {
148+
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
149+
rtio_sqe_drop_all(r);
150+
return;
151+
}
152+
153+
rtio_sqe_prep_callback_no_cqe(complete_op, complete_op_cb, (void *)dev, iodev_sqe);
154+
155+
rtio_submit(r, 0);
156+
}
157+
158+
/**
159+
* @}
160+
*/
161+
162+
#ifdef __cplusplus
163+
}
164+
#endif
165+
166+
#endif /* ZEPHYR_INCLUDE_RTIO_REGMAP_H_ */

0 commit comments

Comments
 (0)