Skip to content

Commit 133da1c

Browse files
gautierg-stnashif
authored andcommitted
drivers: spi: stm32: extend data size support
Extend the number of SPI data sizes supported for series that allow it. The driver uses the new property st,stm32-data-width to create a table with all compatible data widths and to check if the SPI instance support the required width (some instances may have a limited set of widths compared to others on the same SoC). Signed-off-by: Guillaume Gautier <guillaume.gautier-ext@st.com>
1 parent f91258d commit 133da1c

File tree

2 files changed

+158
-47
lines changed

2 files changed

+158
-47
lines changed

drivers/spi/spi_stm32.c

Lines changed: 157 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
70133
static 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)
302378
static 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

323405
static 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

344432
static 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. */
411499
static 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) \

drivers/spi/spi_stm32.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct spi_stm32_config {
3737
#endif
3838
size_t pclk_len;
3939
const struct stm32_pclken *pclken;
40+
int datawidth;
4041
bool fifo_enabled: 1;
4142
bool ioswp: 1;
4243
};

0 commit comments

Comments
 (0)