[PATCH] ASoC: tas2781: Do not report cross-instance writes as errors on SPI
From: Andreas Axelsson
Date: Thu Jun 11 2026 - 04:21:55 EST
On SPI-based TAS2781 HDA systems (e.g. HP laptops with two amplifiers
on separate SPI chip selects), each tasdevice_priv instance services a
single device. The SPI bus glue intentionally returns -EXDEV for
register access addressed to a channel the instance does not own, and
logs it at debug level as "Not error" (see
tasdevice_spi_change_chn_book()).
The shared firmware library does not handle this convention: firmware
blocks explicitly addressed to another device (dev_idx != 0) and
calibration data for other channels are still processed, and the
resulting -EXDEV returns are reported via dev_err and counted as block
errors, triggering pointless retries. This floods the log on every
boot, resume and profile switch:
tas2781-hda spi1-TXNW2781:00-tas2781-hda.0: tasdevice_process_block: bulk_write error = -18
tas2781-hda spi1-TXNW2781:00-tas2781-hda.0: process_block: single write error
tas2781-hda spi1-TXNW2781:00-tas2781-hda.0: chn 1 r0_reg bulk_wr err = -18
Treat -EXDEV as "block not for this instance": skip it silently in
tasdevice_process_block(), keeping the sub-block parsing intact so
the data offset stays correct, and skip foreign channels entirely in
tasdev_load_calibrated_data().
Tested on an HP laptop (subsystem 103C:8DE8) with two TAS2781 amps on
SPI: the error spam is gone, firmware and calibration still load, and
audio is unaffected.
The root cause analysis and fix were developed by Claude (Anthropic AI
assistant); tested by me on the hardware above.
Fixes: 9fa6a693ad8d ("ALSA: hda/tas2781: Remove tas2781_spi_fwlib.c and leverage SND_SOC_TAS2781_FMWLIB")
Signed-off-by: Andreas Axelsson <andreas.axelsson@xxxxxxxxxxxxxxxxx>
---
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -896,6 +896,14 @@
}
}
+ /*
+ * On SPI each instance services a single device, but explicitly
+ * addressed blocks (idx != 0) may target any device. Writes for
+ * a channel this instance does not own return -EXDEV from the
+ * bus glue ("Not error", see tasdevice_spi_change_chn_book);
+ * they are expected and must not be reported as failures. The
+ * block is still parsed so the sub-block offset stays correct.
+ */
for (; chn < chnend; chn++) {
if (tas_priv->tasdevice[chn].is_loading == false)
continue;
@@ -921,7 +929,7 @@
data[subblk_offset + 1],
data[subblk_offset + 2]),
data[subblk_offset + 3]);
- if (rc < 0) {
+ if (rc < 0 && rc != -EXDEV) {
is_err = true;
dev_err(tas_priv->dev,
"process_block: single write error\n");
@@ -953,7 +961,7 @@
data[subblk_offset + 1],
data[subblk_offset + 2]),
&(data[subblk_offset + 4]), len);
- if (rc < 0) {
+ if (rc < 0 && rc != -EXDEV) {
is_err = true;
dev_err(tas_priv->dev,
"%s: bulk_write error = %d\n",
@@ -991,7 +999,7 @@
data[subblk_offset + 4]),
data[subblk_offset + 1],
data[subblk_offset + 5]);
- if (rc < 0) {
+ if (rc < 0 && rc != -EXDEV) {
is_err = true;
dev_err(tas_priv->dev,
"%s: update_bits error = %d\n",
@@ -2552,6 +2560,10 @@
if (!data || !cali_data->total_sz)
return;
+ /* On SPI each instance owns a single device; skip the others. */
+ if (priv->isspi && i != priv->index)
+ return;
+
if (data[k] != i) {
dev_err(priv->dev, "%s: no cal-data for dev %d from usr-spc\n",
__func__, i);