@@ -67,6 +67,69 @@ LOG_MODULE_REGISTER(spi_stm32);
6767#endif
6868#endif /* CONFIG_SOC_SERIES_STM32MP1X */
6969
70+
71+ #define ANY_SPI_DATA_WIDTH_IS (value ) \
72+ (DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_STRING_PROP, \
73+ st_spi_data_width,\
74+ value, STM32_SPI_DATA_WIDTH_) 0)
75+
76+ #define IS_EQ_STRING_PROP (inst , prop , compare_value , prefix ) \
77+ IS_EQ(CONCAT(prefix, DT_INST_STRING_UPPER_TOKEN(inst, prop)), compare_value) ||
78+
79+ /* Data width supported */
80+ #define STM32_SPI_DATA_WIDTH_FULL_4_TO_32_BIT 1
81+ #define STM32_SPI_DATA_WIDTH_FULL_4_TO_16_BIT 2
82+ #define STM32_SPI_DATA_WIDTH_LIMITED_8_16_BIT 3
83+
84+ #if ANY_SPI_DATA_WIDTH_IS (STM32_SPI_DATA_WIDTH_FULL_4_TO_32_BIT ) || \
85+ ANY_SPI_DATA_WIDTH_IS (STM32_SPI_DATA_WIDTH_FULL_4_TO_16_BIT )
86+
87+ #define STM32_SPI_DATA_WIDTH_MIN 4
88+
89+ #if ANY_SPI_DATA_WIDTH_IS (STM32_SPI_DATA_WIDTH_FULL_4_TO_32_BIT )
90+ #define STM32_SPI_DATA_WIDTH_MAX 32
91+ #else
92+ #define STM32_SPI_DATA_WIDTH_MAX 16
93+ #endif
94+
95+ /* These macros are used to create a table containing all supported data widths,
96+ * LL_SPI_DATAWIDTH_x_BIT, with x ranging from 4 to 16 or 32 depending on series.
97+ */
98+ #define STM32_SPI_DATAWIDTH (i , _ ) \
99+ CONCAT(LL_SPI_DATAWIDTH_, UTIL_INC(UTIL_INC(UTIL_INC(UTIL_INC(i)))), BIT)
100+ static const uint32_t table_datawidth [] = {
101+ LISTIFY (UTIL_DEC (UTIL_DEC (UTIL_DEC (STM32_SPI_DATA_WIDTH_MAX ))), STM32_SPI_DATAWIDTH , (,))
102+ };
103+
104+ #else /* ANY FULL_32 || FULL_16 */
105+
106+ static const uint32_t table_datawidth [] = {
107+ LL_SPI_DATAWIDTH_8BIT ,
108+ LL_SPI_DATAWIDTH_16BIT ,
109+ };
110+
111+ #endif /* ANY FULL_32 || FULL_16 */
112+
113+ static bool spi_stm32_is_data_width_supported (const struct device * dev , uint32_t width )
114+ {
115+ const struct spi_stm32_config * cfg = dev -> config ;
116+
117+ switch (cfg -> datawidth ) {
118+ case STM32_SPI_DATA_WIDTH_FULL_4_TO_32_BIT :
119+ return IN_RANGE (width , 4 , 32 );
120+
121+ case STM32_SPI_DATA_WIDTH_FULL_4_TO_16_BIT :
122+ return IN_RANGE (width , 4 , 16 );
123+
124+ case STM32_SPI_DATA_WIDTH_LIMITED_8_16_BIT :
125+ return (width == 8 ) || (width == 16 );
126+
127+ default :
128+ LOG_ERR ("No data width defined for this instance" );
129+ return false;
130+ }
131+ }
132+
70133static void spi_stm32_pm_policy_state_lock_get (const struct device * dev )
71134{
72135 if (IS_ENABLED (CONFIG_PM )) {
@@ -99,6 +162,19 @@ static void spi_stm32_pm_policy_state_lock_put(const struct device *dev)
99162 }
100163}
101164
165+ static uint8_t bits2bytes (spi_operation_t operation )
166+ {
167+ uint32_t bits = SPI_WORD_SIZE_GET (operation );
168+
169+ if (bits <= 8U ) {
170+ return 1U ;
171+ } else if (bits <= 16U ) {
172+ return 2U ;
173+ } else {
174+ return 4U ;
175+ }
176+ }
177+
102178#ifdef CONFIG_SPI_STM32_DMA
103179/* dummy buffer is used for transferring NOP when tx buf is null
104180 * and used as a dummy sink for when rx buf is null.
@@ -302,43 +378,55 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len)
302378static void spi_stm32_send_next_frame (SPI_TypeDef * spi ,
303379 struct spi_stm32_data * data )
304380{
305- const uint8_t frame_size = SPI_WORD_SIZE_GET (data -> ctx .config -> operation );
381+ const uint8_t frame_size = bits2bytes (data -> ctx .config -> operation );
306382 uint32_t tx_frame = SPI_STM32_TX_NOP ;
307383
308- if (frame_size == 8 ) {
384+ if (frame_size == 1U ) {
309385 if (spi_context_tx_buf_on (& data -> ctx )) {
310386 tx_frame = UNALIGNED_GET ((uint8_t * )(data -> ctx .tx_buf ));
311387 }
312388 LL_SPI_TransmitData8 (spi , tx_frame );
313- spi_context_update_tx (& data -> ctx , 1 , 1 );
314- } else {
389+ } else if (frame_size == 2U ) {
315390 if (spi_context_tx_buf_on (& data -> ctx )) {
316391 tx_frame = UNALIGNED_GET ((uint16_t * )(data -> ctx .tx_buf ));
317392 }
318393 LL_SPI_TransmitData16 (spi , tx_frame );
319- spi_context_update_tx (& data -> ctx , 2 , 1 );
394+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
395+ } else {
396+ if (spi_context_tx_buf_on (& data -> ctx )) {
397+ tx_frame = UNALIGNED_GET ((uint32_t * )(data -> ctx .tx_buf ));
398+ }
399+ LL_SPI_TransmitData32 (spi , tx_frame );
400+ #endif
320401 }
402+ spi_context_update_tx (& data -> ctx , frame_size , 1 );
321403}
322404
323405static void spi_stm32_read_next_frame (SPI_TypeDef * spi ,
324406 struct spi_stm32_data * data )
325407{
326- const uint8_t frame_size = SPI_WORD_SIZE_GET (data -> ctx .config -> operation );
408+ const uint8_t frame_size = bits2bytes (data -> ctx .config -> operation );
327409 uint32_t rx_frame = 0 ;
328410
329- if (frame_size == 8 ) {
411+ if (frame_size == 1U ) {
330412 rx_frame = LL_SPI_ReceiveData8 (spi );
331413 if (spi_context_rx_buf_on (& data -> ctx )) {
332414 UNALIGNED_PUT (rx_frame , (uint8_t * )data -> ctx .rx_buf );
333415 }
334- spi_context_update_rx (& data -> ctx , 1 , 1 );
335- } else {
416+ } else if (frame_size == 2U ) {
336417 rx_frame = LL_SPI_ReceiveData16 (spi );
337418 if (spi_context_rx_buf_on (& data -> ctx )) {
338419 UNALIGNED_PUT (rx_frame , (uint16_t * )data -> ctx .rx_buf );
339420 }
340- spi_context_update_rx (& data -> ctx , 2 , 1 );
421+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
422+ } else {
423+ rx_frame = LL_SPI_ReceiveData32 (spi );
424+ if (spi_context_rx_buf_on (& data -> ctx )) {
425+ UNALIGNED_PUT (rx_frame , (uint32_t * )data -> ctx .rx_buf );
426+ }
427+ #endif
341428 }
429+ spi_context_update_rx (& data -> ctx , frame_size , 1 );
342430}
343431
344432static bool spi_stm32_transfer_ongoing (struct spi_stm32_data * data )
@@ -410,35 +498,44 @@ static void spi_stm32_shift_m(const struct spi_stm32_config *cfg,
410498/* Shift a SPI frame as slave. */
411499static void spi_stm32_shift_s (SPI_TypeDef * spi , struct spi_stm32_data * data )
412500{
501+ uint8_t frame_size = bits2bytes (data -> ctx .config -> operation );
502+
413503 if (ll_func_tx_is_not_full (spi ) && spi_context_tx_on (& data -> ctx )) {
414- uint16_t tx_frame ;
504+ uint32_t tx_frame ;
415505
416- if (SPI_WORD_SIZE_GET ( data -> ctx . config -> operation ) == 8 ) {
506+ if (frame_size == 1U ) {
417507 tx_frame = UNALIGNED_GET ((uint8_t * )(data -> ctx .tx_buf ));
418508 LL_SPI_TransmitData8 (spi , tx_frame );
419- spi_context_update_tx (& data -> ctx , 1 , 1 );
420- } else {
509+ } else if (frame_size == 2U ) {
421510 tx_frame = UNALIGNED_GET ((uint16_t * )(data -> ctx .tx_buf ));
422511 LL_SPI_TransmitData16 (spi , tx_frame );
423- spi_context_update_tx (& data -> ctx , 2 , 1 );
512+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
513+ } else {
514+ tx_frame = UNALIGNED_GET ((uint32_t * )(data -> ctx .tx_buf ));
515+ LL_SPI_TransmitData32 (spi , tx_frame );
516+ #endif
424517 }
518+ spi_context_update_tx (& data -> ctx , frame_size , 1 );
425519 } else {
426520 ll_func_disable_int_tx_empty (spi );
427521 }
428522
429- if (ll_func_rx_is_not_empty (spi ) &&
430- spi_context_rx_buf_on (& data -> ctx )) {
431- uint16_t rx_frame ;
523+ if (ll_func_rx_is_not_empty (spi ) && spi_context_rx_buf_on (& data -> ctx )) {
524+ uint32_t rx_frame ;
432525
433- if (SPI_WORD_SIZE_GET ( data -> ctx . config -> operation ) == 8 ) {
526+ if (frame_size == 1U ) {
434527 rx_frame = LL_SPI_ReceiveData8 (spi );
435528 UNALIGNED_PUT (rx_frame , (uint8_t * )data -> ctx .rx_buf );
436- spi_context_update_rx (& data -> ctx , 1 , 1 );
437- } else {
529+ } else if (frame_size == 2U ) {
438530 rx_frame = LL_SPI_ReceiveData16 (spi );
439531 UNALIGNED_PUT (rx_frame , (uint16_t * )data -> ctx .rx_buf );
440- spi_context_update_rx (& data -> ctx , 2 , 1 );
532+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
533+ } else {
534+ rx_frame = LL_SPI_ReceiveData32 (spi );
535+ UNALIGNED_PUT (rx_frame , (uint32_t * )data -> ctx .rx_buf );
536+ #endif
441537 }
538+ spi_context_update_rx (& data -> ctx , frame_size , 1 );
442539 }
443540}
444541
@@ -703,8 +800,17 @@ static void spi_stm32_complete(const struct device *dev, int status)
703800#endif /* compat st_stm32_spi_fifo*/
704801
705802 if (LL_SPI_GetMode (spi ) == LL_SPI_MODE_MASTER ) {
706- while (ll_func_spi_is_busy (spi )) {
707- /* NOP */
803+ while (ll_func_spi_is_busy (spi ) && LL_SPI_IsEnabled (spi )) {
804+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
805+ uint32_t width = SPI_WORD_SIZE_GET (data -> ctx .config -> operation );
806+ /* In non-FIFO mode, the TXC flag is not raised at the end of 9, 17 or 25
807+ * bit transfer, so disable the SPI in these cases to avoid being stuck.
808+ */
809+ if (!cfg -> fifo_enabled &&
810+ ((width == 9U ) || (width == 17U ) || (width == 25U ))) {
811+ ll_func_disable_spi (spi );
812+ }
813+ #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */
708814 }
709815
710816 spi_stm32_cs_control (dev , false);
@@ -842,8 +948,7 @@ static int spi_stm32_configure(const struct device *dev,
842948 }
843949#endif /* CONFIG_SPI_RTIO */
844950
845- if ((SPI_WORD_SIZE_GET (config -> operation ) != 8 ) &&
846- (SPI_WORD_SIZE_GET (config -> operation ) != 16 )) {
951+ if (!spi_stm32_is_data_width_supported (dev , SPI_WORD_SIZE_GET (config -> operation ))) {
847952 return - ENOTSUP ;
848953 }
849954
@@ -959,11 +1064,13 @@ static int spi_stm32_configure(const struct device *dev,
9591064 LL_SPI_SetMode (spi , LL_SPI_MODE_MASTER );
9601065 }
9611066
962- if (SPI_WORD_SIZE_GET (config -> operation ) == 8 ) {
963- LL_SPI_SetDataWidth (spi , LL_SPI_DATAWIDTH_8BIT );
964- } else {
965- LL_SPI_SetDataWidth (spi , LL_SPI_DATAWIDTH_16BIT );
966- }
1067+ #if ANY_SPI_DATA_WIDTH_IS (STM32_SPI_DATA_WIDTH_FULL_4_TO_32_BIT ) || \
1068+ ANY_SPI_DATA_WIDTH_IS (STM32_SPI_DATA_WIDTH_FULL_4_TO_16_BIT )
1069+ LL_SPI_SetDataWidth (spi , table_datawidth [SPI_WORD_SIZE_GET (config -> operation ) -
1070+ STM32_SPI_DATA_WIDTH_MIN ]);
1071+ #else
1072+ LL_SPI_SetDataWidth (spi , table_datawidth [bits2bytes (config -> operation ) - 1U ]);
1073+ #endif
9671074
9681075#if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
9691076 LL_SPI_SetMasterSSIdleness (spi , cfg -> mssi_clocks );
@@ -1015,7 +1122,7 @@ static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config,
10151122 num_bytes += bufs -> buffers [i ].len ;
10161123 }
10171124
1018- uint8_t bytes_per_frame = SPI_WORD_SIZE_GET (config -> operation ) / BITS_PER_BYTE ;
1125+ uint8_t bytes_per_frame = bits2bytes (config -> operation );
10191126
10201127 if ((num_bytes % bytes_per_frame ) != 0 ) {
10211128 return - EINVAL ;
@@ -1068,8 +1175,7 @@ static int spi_stm32_half_duplex_switch_to_receive(const struct spi_stm32_config
10681175
10691176 if (SPI_OP_MODE_GET (config -> operation ) == SPI_OP_MODE_MASTER ) {
10701177 int num_bytes = spi_context_total_rx_len (& data -> ctx );
1071- uint8_t bytes_per_frame = SPI_WORD_SIZE_GET (config -> operation ) /
1072- BITS_PER_BYTE ;
1178+ uint8_t bytes_per_frame = bits2bytes (config -> operation );
10731179
10741180 if ((num_bytes % bytes_per_frame ) != 0 ) {
10751181 return - EINVAL ;
@@ -1163,11 +1269,7 @@ static int transceive(const struct device *dev,
11631269 }
11641270
11651271 /* Set buffers info */
1166- if (SPI_WORD_SIZE_GET (config -> operation ) == 8 ) {
1167- spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , 1 );
1168- } else {
1169- spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , 2 );
1170- }
1272+ spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , bits2bytes (config -> operation ));
11711273
11721274 uint32_t transfer_dir = LL_SPI_GetTransferDirection (spi );
11731275
@@ -1344,11 +1446,7 @@ static int transceive_dma(const struct device *dev,
13441446#endif /* st_stm32h7_spi */
13451447
13461448 /* Set buffers info */
1347- if (SPI_WORD_SIZE_GET (config -> operation ) == 8 ) {
1348- spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , 1 );
1349- } else {
1350- spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , 2 );
1351- }
1449+ spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , bits2bytes (config -> operation ));
13521450
13531451#if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
13541452 /* set request before enabling (else SPI CFG1 reg is write protected) */
@@ -1377,7 +1475,7 @@ static int transceive_dma(const struct device *dev,
13771475 /* This is turned off in spi_stm32_complete(). */
13781476 spi_stm32_cs_control (dev , true);
13791477
1380- uint8_t word_size_bytes = SPI_WORD_SIZE_GET (config -> operation ) / BITS_PER_BYTE ;
1478+ uint8_t word_size_bytes = bits2bytes (config -> operation );
13811479 struct dma_config * rx_cfg = & data -> dma_rx .dma_cfg , * tx_cfg = & data -> dma_tx .dma_cfg ;
13821480
13831481 rx_cfg -> source_data_size = rx_cfg -> source_burst_length = word_size_bytes ;
@@ -1448,7 +1546,17 @@ static int transceive_dma(const struct device *dev,
14481546 k_yield ());
14491547#else
14501548 /* wait until spi is no more busy (spi TX fifo is really empty) */
1451- while (ll_func_spi_dma_busy (spi )) {
1549+ while (ll_func_spi_dma_busy (spi ) && LL_SPI_IsEnabled (spi )) {
1550+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32h7_spi )
1551+ uint32_t width = SPI_WORD_SIZE_GET (data -> ctx .config -> operation );
1552+ /* The TXC flag is not raised at the end of 9, 17 or 25
1553+ * bit transfer, so disable the SPI in these cases to avoid being stuck.
1554+ */
1555+ if ((width == 9U ) || (width == 17U ) || (width == 25U )) {
1556+ k_usleep (1000 );
1557+ ll_func_disable_spi (spi );
1558+ }
1559+ #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */
14521560 }
14531561#endif /* CONFIG_SPI_STM32_ERRATA_BUSY */
14541562
@@ -1458,7 +1566,7 @@ static int transceive_dma(const struct device *dev,
14581566 LL_SPI_DisableDMAReq_RX (spi );
14591567#endif /* ! st_stm32h7_spi */
14601568
1461- uint8_t frame_size_bytes = SPI_WORD_SIZE_GET (config -> operation ) / BITS_PER_BYTE ;
1569+ uint8_t frame_size_bytes = bits2bytes (config -> operation );
14621570
14631571 if (transfer_dir == LL_SPI_FULL_DUPLEX ) {
14641572 spi_context_update_tx (& data -> ctx , frame_size_bytes , dma_len );
@@ -1774,6 +1882,8 @@ static int spi_stm32_init(const struct device *dev)
17741882 .pclken = pclken_##id, \
17751883 .pclk_len = DT_INST_NUM_CLOCKS(id), \
17761884 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
1885+ .datawidth = CONCAT(STM32_SPI_DATA_WIDTH_, \
1886+ DT_INST_STRING_UPPER_TOKEN(id, st_spi_data_width)), \
17771887 .fifo_enabled = SPI_FIFO_ENABLED(id), \
17781888 .ioswp = DT_INST_PROP(id, ioswp), \
17791889 STM32_SPI_IRQ_HANDLER_FUNC(id) \
0 commit comments