@@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
2525#include <zephyr/pm/policy.h>
2626#include <zephyr/pm/device.h>
2727#include <zephyr/pm/device_runtime.h>
28+ #include <zephyr/rtio/rtio.h>
2829#include <zephyr/sys/util.h>
2930#include <zephyr/toolchain.h>
3031
@@ -538,12 +539,147 @@ static void spi_stm32_msg_start(const struct device *dev, bool is_rx_empty)
538539#endif /* CONFIG_SPI_STM32_INTERRUPT */
539540}
540541
542+ #ifdef CONFIG_SPI_RTIO
543+ /* Forward declaration for RTIO handlers conveniance */
544+ static void spi_stm32_iodev_complete (const struct device * dev , int status );
545+ static int spi_stm32_configure (const struct device * dev ,
546+ const struct spi_config * config ,
547+ bool write );
548+
549+ static void spi_stm32_iodev_msg_start (const struct device * dev , struct spi_config * config ,
550+ const uint8_t * tx_buf , uint8_t * rx_buf , uint32_t buf_len )
551+ {
552+ struct spi_stm32_data * data = dev -> data ;
553+ uint32_t size = buf_len / (SPI_WORD_SIZE_GET (config -> operation ) / BITS_PER_BYTE );
554+
555+ const struct spi_buf current_tx = {.buf = NULL , .len = size };
556+ const struct spi_buf current_rx = {.buf = NULL , .len = size };
557+
558+ data -> ctx .current_tx = & current_tx ;
559+ data -> ctx .current_rx = & current_rx ;
560+
561+ data -> ctx .tx_buf = tx_buf ;
562+ data -> ctx .rx_buf = rx_buf ;
563+ data -> ctx .tx_len = tx_buf != NULL ? size : 0 ;
564+ data -> ctx .rx_len = rx_buf != NULL ? size : 0 ;
565+ data -> ctx .tx_count = tx_buf != NULL ? 1 : 0 ;
566+ data -> ctx .rx_count = rx_buf != NULL ? 1 : 0 ;
567+
568+ data -> ctx .sync_status = 0 ;
569+
570+ #ifdef CONFIG_SPI_SLAVE
571+ ctx -> recv_frames = 0 ;
572+ #endif /* CONFIG_SPI_SLAVE */
573+
574+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
575+ const struct spi_stm32_config * cfg = dev -> config ;
576+ SPI_TypeDef * spi = cfg -> spi ;
577+
578+ if (cfg -> fifo_enabled && SPI_OP_MODE_GET (config -> operation ) == SPI_OP_MODE_MASTER ) {
579+ LL_SPI_SetTransferSize (spi , size );
580+ }
581+ #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */
582+
583+ spi_stm32_msg_start (dev , rx_buf == NULL );
584+ }
585+
586+ static void spi_stm32_iodev_start (const struct device * dev )
587+ {
588+ struct spi_stm32_data * data = dev -> data ;
589+ struct spi_rtio * rtio_ctx = data -> rtio_ctx ;
590+ struct spi_dt_spec * spi_dt_spec = rtio_ctx -> txn_curr -> sqe .iodev -> data ;
591+ struct spi_config * spi_config = & spi_dt_spec -> config ;
592+ struct rtio_sqe * sqe = & rtio_ctx -> txn_curr -> sqe ;
593+
594+ switch (sqe -> op ) {
595+ case RTIO_OP_RX :
596+ spi_stm32_iodev_msg_start (dev , spi_config , NULL , sqe -> rx .buf , sqe -> rx .buf_len );
597+ break ;
598+ case RTIO_OP_TX :
599+ spi_stm32_iodev_msg_start (dev , spi_config , sqe -> tx .buf , NULL , sqe -> tx .buf_len );
600+ break ;
601+ case RTIO_OP_TINY_TX :
602+ spi_stm32_iodev_msg_start (dev , spi_config , sqe -> tiny_tx .buf , NULL ,
603+ sqe -> tiny_tx .buf_len );
604+ break ;
605+ case RTIO_OP_TXRX :
606+ spi_stm32_iodev_msg_start (dev , spi_config , sqe -> txrx .tx_buf , sqe -> txrx .rx_buf ,
607+ sqe -> txrx .buf_len );
608+ break ;
609+ default :
610+ LOG_ERR ("Invalid op code %d for submission %p" , sqe -> op , (void * )sqe );
611+ spi_stm32_iodev_complete (dev , - EINVAL );
612+ break ;
613+ }
614+ }
615+
616+ static inline int spi_stm32_iodev_prepare_start (const struct device * dev )
617+ {
618+ struct spi_stm32_data * data = dev -> data ;
619+ struct spi_rtio * rtio_ctx = data -> rtio_ctx ;
620+ struct spi_dt_spec * spi_dt_spec = rtio_ctx -> txn_curr -> sqe .iodev -> data ;
621+ struct spi_config * spi_config = & spi_dt_spec -> config ;
622+ uint8_t op_code = rtio_ctx -> txn_curr -> sqe .op ;
623+ bool write = (op_code == RTIO_OP_TX ) ||
624+ (op_code == RTIO_OP_TINY_TX ) ||
625+ (op_code == RTIO_OP_TXRX );
626+
627+ return spi_stm32_configure (dev , spi_config , write );
628+ }
629+
630+ static void spi_stm32_iodev_complete (const struct device * dev , int status )
631+ {
632+ struct spi_stm32_data * data = dev -> data ;
633+ struct spi_rtio * rtio_ctx = data -> rtio_ctx ;
634+
635+ if (status == 0 && (rtio_ctx -> txn_curr -> sqe .flags & RTIO_SQE_TRANSACTION ) != 0 ) {
636+ rtio_ctx -> txn_curr = rtio_txn_next (rtio_ctx -> txn_curr );
637+ spi_stm32_iodev_start (dev );
638+ } else {
639+ spi_stm32_cs_control (dev , false);
640+ while (spi_rtio_complete (rtio_ctx , status )) {
641+ status = spi_stm32_iodev_prepare_start (dev );
642+ if (status == 0 ) {
643+ spi_stm32_iodev_start (dev );
644+ break ;
645+ }
646+
647+ /* Clear chip select and loop to mark transfer completed with an error */
648+ spi_stm32_cs_control (dev , false);
649+ }
650+ }
651+ }
652+
653+ static void spi_stm32_iodev_submit (const struct device * dev , struct rtio_iodev_sqe * iodev_sqe )
654+ {
655+ struct spi_stm32_data * data = dev -> data ;
656+ struct spi_rtio * rtio_ctx = data -> rtio_ctx ;
657+ int err ;
658+
659+ if (spi_rtio_submit (rtio_ctx , iodev_sqe )) {
660+ err = spi_stm32_iodev_prepare_start (dev );
661+ if (err == 0 ) {
662+ spi_stm32_iodev_start (dev );
663+ } else {
664+ spi_stm32_iodev_complete (dev , err );
665+ }
666+ }
667+ }
668+ #endif /* CONFIG_SPI_RTIO */
669+
541670static void spi_stm32_complete (const struct device * dev , int status )
542671{
543672 const struct spi_stm32_config * cfg = dev -> config ;
544673 SPI_TypeDef * spi = cfg -> spi ;
545674 struct spi_stm32_data * data = dev -> data ;
546675
676+ #ifdef CONFIG_SPI_RTIO
677+ if (data -> rtio_ctx -> txn_head != NULL ) {
678+ spi_stm32_iodev_complete (dev , status );
679+ return ;
680+ }
681+ #endif /* CONFIG_SPI_RTIO */
682+
547683#ifdef CONFIG_SPI_STM32_INTERRUPT
548684 ll_func_disable_int_tx_empty (spi );
549685 ll_func_disable_int_rx_not_empty (spi );
@@ -618,6 +754,15 @@ static void spi_stm32_isr(const struct device *dev)
618754 SPI_TypeDef * spi = cfg -> spi ;
619755 int err ;
620756
757+ #if defined(CONFIG_SPI_RTIO )
758+ /* With RTIO, an interrupt can occur even though they
759+ * are all previously disabled. Ignore it then.
760+ */
761+ if (ll_func_are_int_disabled (spi )) {
762+ return ;
763+ }
764+ #endif /* CONFIG_SPI_RTIO */
765+
621766 /* Some spurious interrupts are triggered when SPI is not enabled; ignore them.
622767 * Do it only when fifo is enabled to leave non-fifo functionality untouched for now
623768 */
@@ -679,6 +824,7 @@ static int spi_stm32_configure(const struct device *dev,
679824 uint32_t clock ;
680825 int br ;
681826
827+ #ifndef CONFIG_SPI_RTIO
682828 if (spi_context_configured (& data -> ctx , config )) {
683829 if (config -> operation & SPI_HALF_DUPLEX ) {
684830 if (write ) {
@@ -689,6 +835,7 @@ static int spi_stm32_configure(const struct device *dev,
689835 }
690836 return 0 ;
691837 }
838+ #endif /* CONFIG_SPI_RTIO */
692839
693840 if ((SPI_WORD_SIZE_GET (config -> operation ) != 8 ) &&
694841 (SPI_WORD_SIZE_GET (config -> operation ) != 16 )) {
@@ -839,6 +986,8 @@ static int spi_stm32_release(const struct device *dev,
839986 return 0 ;
840987}
841988
989+ #ifndef CONFIG_SPI_RTIO
990+
842991#if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
843992static int32_t spi_stm32_count_bufset_frames (const struct spi_config * config ,
844993 const struct spi_buf_set * bufs )
@@ -957,6 +1106,7 @@ static int spi_stm32_half_duplex_switch_to_receive(const struct spi_stm32_config
9571106
9581107 return 0 ;
9591108}
1109+ #endif /* !CONFIG_SPI_RTIO */
9601110
9611111static int transceive (const struct device * dev ,
9621112 const struct spi_config * config ,
@@ -966,9 +1116,7 @@ static int transceive(const struct device *dev,
9661116 spi_callback_t cb ,
9671117 void * userdata )
9681118{
969- const struct spi_stm32_config * cfg = dev -> config ;
9701119 struct spi_stm32_data * data = dev -> data ;
971- SPI_TypeDef * spi = cfg -> spi ;
9721120 int ret ;
9731121
9741122 if (tx_bufs == NULL && rx_bufs == NULL ) {
@@ -983,6 +1131,12 @@ static int transceive(const struct device *dev,
9831131
9841132 spi_stm32_pm_policy_state_lock_get (dev );
9851133
1134+ #ifdef CONFIG_SPI_RTIO
1135+ ret = spi_rtio_transceive (data -> rtio_ctx , config , tx_bufs , rx_bufs );
1136+ #else /* CONFIG_SPI_RTIO */
1137+ const struct spi_stm32_config * cfg = dev -> config ;
1138+ SPI_TypeDef * spi = cfg -> spi ;
1139+
9861140 ret = spi_stm32_configure (dev , config , tx_bufs != NULL );
9871141 if (ret != 0 ) {
9881142 goto end ;
@@ -1050,6 +1204,8 @@ static int transceive(const struct device *dev,
10501204#endif /* CONFIG_SPI_STM32_INTERRUPT */
10511205
10521206end :
1207+ #endif /* CONFIG_SPI_RTIO */
1208+
10531209 spi_context_release (& data -> ctx , ret );
10541210
10551211 return ret ;
@@ -1383,7 +1539,7 @@ static DEVICE_API(spi, api_funcs) = {
13831539 .transceive_async = spi_stm32_transceive_async ,
13841540#endif
13851541#ifdef CONFIG_SPI_RTIO
1386- .iodev_submit = spi_rtio_iodev_default_submit ,
1542+ .iodev_submit = spi_stm32_iodev_submit ,
13871543#endif
13881544 .release = spi_stm32_release ,
13891545};
@@ -1507,6 +1663,10 @@ static int spi_stm32_init(const struct device *dev)
15071663
15081664#endif /* CONFIG_SPI_STM32_DMA */
15091665
1666+ #ifdef CONFIG_SPI_RTIO
1667+ spi_rtio_init (data -> rtio_ctx , dev );
1668+ #endif /* CONFIG_SPI_RTIO */
1669+
15101670 return pm_device_driver_init (dev , spi_stm32_pm_action );
15111671}
15121672
@@ -1602,13 +1762,19 @@ static int spi_stm32_init(const struct device *dev)
16021762 (.mssi_clocks = DT_INST_PROP(id, mssi_clock),)) \
16031763 }; \
16041764 \
1765+ IF_ENABLED(CONFIG_SPI_RTIO, \
1766+ (SPI_RTIO_DEFINE(spi_stm32_rtio_##id, \
1767+ CONFIG_SPI_STM32_RTIO_SQ_SIZE, \
1768+ CONFIG_SPI_STM32_RTIO_CQ_SIZE))) \
1769+ \
16051770 static struct spi_stm32_data spi_stm32_dev_data_##id = { \
16061771 SPI_CONTEXT_INIT_LOCK(spi_stm32_dev_data_##id, ctx), \
16071772 SPI_CONTEXT_INIT_SYNC(spi_stm32_dev_data_##id, ctx), \
16081773 SPI_DMA_CHANNEL(id, rx, RX, PERIPHERAL, MEMORY) \
16091774 SPI_DMA_CHANNEL(id, tx, TX, MEMORY, PERIPHERAL) \
16101775 SPI_DMA_STATUS_SEM(id) \
16111776 SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx) \
1777+ IF_ENABLED(CONFIG_SPI_RTIO, (.rtio_ctx = &spi_stm32_rtio_##id,))\
16121778 }; \
16131779 \
16141780 PM_DEVICE_DT_INST_DEFINE(id, spi_stm32_pm_action); \
0 commit comments