[PATCH v2] ALSA: hda/tas2781: Add hardware stabilization delay during firmware load retries

Zeliang Li via B4 Relay <[email protected]>
Newsgroups gmane.linux.sound,gmane.linux.kernel
Message-ID <[email protected]>
From: Zeliang Li <[email protected]>

During runtime resume transitions, loading calibration data blocks
to the tas2781 amplifier may intermittently trigger transmission
failures or block checksum mismatches (-EAGAIN) due to un-stabilized
power rails or I2C bus glitches.

The loop in tasdev_load_blk() decrements block->nr_retry and attempts
an immediate re-transmission upon receiving -EAGAIN. However, without
any inter-retry delay, all available retry slots are exhausted within
less than a microsecond—long before the hardware can physically
settle. This leads to permanent "ERROR_PRAM_CRCCHK" deadlocks and
silent speakers on modern laptops after resuming media.

Fix this cleanly by introducing a 2ms usleep_range() delay directly
inside the tasdev_load_blk() retry paths prior to each 'continue'
statement. This grants the chip sufficient time to stabilize before
the next transmission attempt without introducing unnecessary latency
on final failures.

Signed-off-by: Zeliang Li <[email protected]>
---
 sound/soc/codecs/tas2781-fmwlib.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index dcbeb9618195..bfabff583d57 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
 			}
 		}
 		if (ret == -EAGAIN) {
-			if (block->nr_retry > 0)
+			if (block->nr_retry > 0) {
+				/* Give the hardware time to stabilize before
+				 * next block re-transmission attempt.
+				 */
+				usleep_range(2000, 2500);
 				continue;
+			}
 		} else if (ret < 0) /*err in current device, skip it*/
 			break;
 
 		if (block->is_pchksum_present) {
 			ret = tasdev_block_chksum(tas_priv, block, chn);
 			if (ret == -EAGAIN) {
-				if (block->nr_retry > 0)
+				if (block->nr_retry > 0) {
+					/* Give the bus time to recover after
+					 * a checksum mismatch error.
+					 */
+					usleep_range(2000, 2500);
 					continue;
+				}
 			} else if (ret < 0) /*err in current device, skip it*/
 				break;
 		}

---
base-commit: a5161661ae99f497affa83a5b8654e457cda6267
change-id: 20260815-master-a8aeb8653733

Best regards,
-- 
Zeliang Li <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.