Skip to content

Commit 40b3d08

Browse files
dlechbroonie
authored andcommitted
spi: axi-spi-engine: fix sleep calculation
The sleep calculation was not taking into account increased delay when the SPI device is not running at the maximum SCLK frequency. Rounding down when one SCLK tick was the same as the instruction execution time was fine, but it rounds down too much when SCLK is slower. This changes the rounding to round up instead while still taking into account the instruction execution time so that small delays remain accurate. Fixes: be9070b ("spi: axi-spi-engine: fix sleep ticks calculation") Signed-off-by: David Lechner <[email protected]> Link: https://patch.msgid.link/20240620-spi-axi-spi-engine-fix-sleep-time-v1-1-b20b527924a0@baylibre.com Signed-off-by: Mark Brown <[email protected]>
1 parent ce1dac5 commit 40b3d08

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

drivers/spi/spi-axi-spi-engine.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,20 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
164164
}
165165

166166
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
167-
int delay_ns, u32 sclk_hz)
167+
int delay_ns, int inst_ns, u32 sclk_hz)
168168
{
169169
unsigned int t;
170170

171-
/* negative delay indicates error, e.g. from spi_delay_to_ns() */
172-
if (delay_ns <= 0)
171+
/*
172+
* Negative delay indicates error, e.g. from spi_delay_to_ns(). And if
173+
* delay is less that the instruction execution time, there is no need
174+
* for an extra sleep instruction since the instruction execution time
175+
* will already cover the required delay.
176+
*/
177+
if (delay_ns < 0 || delay_ns <= inst_ns)
173178
return;
174179

175-
/* rounding down since executing the instruction adds a couple of ticks delay */
176-
t = DIV_ROUND_DOWN_ULL((u64)delay_ns * sclk_hz, NSEC_PER_SEC);
180+
t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC);
177181
while (t) {
178182
unsigned int n = min(t, 256U);
179183

@@ -220,10 +224,16 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
220224
struct spi_device *spi = msg->spi;
221225
struct spi_controller *host = spi->controller;
222226
struct spi_transfer *xfer;
223-
int clk_div, new_clk_div;
227+
int clk_div, new_clk_div, inst_ns;
224228
bool keep_cs = false;
225229
u8 bits_per_word = 0;
226230

231+
/*
232+
* Take into account instruction execution time for more accurate sleep
233+
* times, especially when the delay is small.
234+
*/
235+
inst_ns = DIV_ROUND_UP(NSEC_PER_SEC, host->max_speed_hz);
236+
227237
clk_div = 1;
228238

229239
spi_engine_program_add_cmd(p, dry,
@@ -252,7 +262,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
252262

253263
spi_engine_gen_xfer(p, dry, xfer);
254264
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
255-
xfer->effective_speed_hz);
265+
inst_ns, xfer->effective_speed_hz);
256266

257267
if (xfer->cs_change) {
258268
if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
@@ -262,7 +272,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
262272
spi_engine_gen_cs(p, dry, spi, false);
263273

264274
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(
265-
&xfer->cs_change_delay, xfer),
275+
&xfer->cs_change_delay, xfer), inst_ns,
266276
xfer->effective_speed_hz);
267277

268278
if (!list_next_entry(xfer, transfer_list)->cs_off)

0 commit comments

Comments
 (0)