[PATCH 3/8] spi: atcspi200: Use proper timeout handling for busy-wait loops
Leo Yu-Chi Liang
ycliang at andestech.com
Fri Apr 17 04:20:59 CEST 2026
Replace manual busy-wait counters with standard U-Boot timeout APIs:
- Use wait_for_bit_le32() for FIFO reset wait in claim_bus and SPI
busy wait in stop, providing time-based timeouts with watchdog
support
- Use get_timer() for the transfer polling loop where TX/RX work
is done inside the loop
- Remove the 'to' field from private data (no longer needed)
- Replace iteration-count SPI_TIMEOUT with time-based SPI_TIMEOUT_MS
Signed-off-by: Leo Yu-Chi Liang <ycliang at andestech.com>
---
drivers/spi/atcspi200_spi.c | 41 ++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index 33cf7583581..38345a88260 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -11,13 +11,15 @@
#include <dm/device_compat.h>
#include <log.h>
#include <spi.h>
+#include <time.h>
+#include <wait_bit.h>
#include <asm/io.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#define MAX_TRANSFER_LEN 512
#define CHUNK_SIZE 1
-#define SPI_TIMEOUT 0x100000
+#define SPI_TIMEOUT_MS 1000
#define SPI_DEF_SRC_CLK 100000000
#define SPI_DEF_MAX_CLK 40000000
@@ -68,7 +70,6 @@
struct atcspi200_priv {
void *regs;
- int to;
unsigned int freq;
unsigned int src_clk;
unsigned int max_clk;
@@ -126,14 +127,16 @@ static int atcspi200_hw_set_speed(struct atcspi200_priv *priv)
static int atcspi200_hw_claim_bus(struct atcspi200_priv *priv)
{
unsigned int format;
+ int ret;
atcspi200_write(priv, ATCSPI200_REG_CTRL,
atcspi200_read(priv, ATCSPI200_REG_CTRL) |
TXFRST | RXFRST | SPIRST);
- while ((atcspi200_read(priv, ATCSPI200_REG_CTRL) &
- (TXFRST | RXFRST | SPIRST)) && priv->to--)
- if (!priv->to)
- return -EINVAL;
+ ret = wait_for_bit_le32(priv->regs + ATCSPI200_REG_CTRL,
+ TXFRST | RXFRST | SPIRST,
+ false, SPI_TIMEOUT_MS, false);
+ if (ret)
+ return ret;
priv->cmd_len = 0;
format = priv->mode | FIELD_PREP(DATA_LEN_MASK, 8 - 1);
@@ -176,12 +179,8 @@ static int atcspi200_hw_start(struct atcspi200_priv *priv)
static int atcspi200_hw_stop(struct atcspi200_priv *priv)
{
- while ((atcspi200_read(priv, ATCSPI200_REG_STATUS) & SPIBSY) &&
- priv->to--)
- if (!priv->to)
- return -EINVAL;
-
- return 0;
+ return wait_for_bit_le32(priv->regs + ATCSPI200_REG_STATUS,
+ SPIBSY, false, SPI_TIMEOUT_MS, false);
}
static void atcspi200_tx_byte(struct atcspi200_priv *priv, const void *dout)
@@ -209,7 +208,8 @@ static int atcspi200_hw_xfer(struct atcspi200_priv *priv,
size_t cmd_len = priv->cmd_len;
unsigned long data_len = bitlen / 8;
int rf_cnt;
- int ret = 0, timeout = 0;
+ int ret = 0;
+ unsigned long start;
max_tran_len = priv->max_transfer_length;
switch (flags) {
@@ -252,12 +252,17 @@ static int atcspi200_hw_xfer(struct atcspi200_priv *priv,
priv->tran_len = tran_len;
num_blks = DIV_ROUND_UP(tran_len, CHUNK_SIZE);
num_bytes = tran_len % CHUNK_SIZE;
- timeout = SPI_TIMEOUT;
if (num_bytes == 0)
num_bytes = CHUNK_SIZE;
+ start = get_timer(0);
atcspi200_hw_start(priv);
- while (num_blks && timeout--) {
+ while (num_blks) {
+ if (get_timer(start) > SPI_TIMEOUT_MS) {
+ debug("spi_xfer: %s() timeout\n", __func__);
+ break;
+ }
+
event = atcspi200_read(priv, ATCSPI200_REG_STATUS);
if ((event & TXEPTY) && data_out) {
@@ -282,11 +287,6 @@ static int atcspi200_hw_xfer(struct atcspi200_priv *priv,
din = (unsigned char *)din + rx_bytes;
}
}
-
- if (!timeout) {
- debug("spi_xfer: %s() timeout\n", __func__);
- break;
- }
}
data_len -= tran_len;
@@ -385,7 +385,6 @@ static int atcspi200_spi_probe(struct udevice *bus)
{
struct atcspi200_priv *priv = dev_get_priv(bus);
- priv->to = SPI_TIMEOUT;
priv->max_transfer_length = MAX_TRANSFER_LEN;
atcspi200_spi_get_clk(bus);
--
2.34.1
More information about the U-Boot
mailing list