[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