[PATCH v2 5/5] spi: atmel: use the maximum divider for an unspecified speed

From: shao.mingyin

Date: Tue Nov 10 2026 - 10:45:37 EST


From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>

atmel_spi_set_xfer_speed() divides by xfer->speed_hz. That speed can
remain zero when neither the device nor the controller supplies a
maximum, allowing a transfer to reach the divider calculation with a
zero divisor.

Select the maximum SCBR value directly when the speed is zero. This
avoids both the division and an out-of-range divider that would be
rejected by the subsequent validation. Keep the existing range checks
for explicitly requested speeds.

Fixes: d3b72c7e6bf3 ("spi: atmel: add support for changing message transfer speed")
Suggested-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
v2:
- select SCBR=255 directly for a zero speed, avoiding the division
and the subsequent rejection of an out-of-range divider (Mark Brown)
- preserve the range checks for nonzero requested speeds
v1: https://lore.kernel.org/all/20261106234803459Z94udUX-Ai29-OfBFRND6@xxxxxxxxxx/

Validation on x86-64 with GCC 13 and UBSAN: the verbatim speed-setting
function ran with clock/register stubs for v1/v2 controllers and native
or GPIO chip selects. Zero speed bypassed division, programmed SCBR=255
and set effective_speed_hz. Nonzero speeds retained the existing
SCBR=0 and SCBR>=256 rejections and the valid-divider register values.

drivers/spi/spi-atmel.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ffc896e4621acf2f2abfd33981904fae40b08ff5..333423b3111f8b04fbb314da659fc4ac99a390fa 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -923,7 +923,10 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
* Calculate the lowest divider that satisfies the
* constraint, assuming div32/fdiv/mbz == 0.
*/
- scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
+ if (xfer->speed_hz)
+ scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
+ else
+ scbr = (1 << SPI_SCBR_SIZE) - 1;

/*
* If the resulting divider doesn't fit into the