[PATCH v2] ASoC: tas2783-sdw: add firmware download status check

From: Baojun Xu

Date: Wed Aug 12 2026 - 22:15:41 EST


Currently, the firmware download is unnecessarily triggered on every
system resume from suspend, causing significant wake-up latency. However,
this step is redundant if the AMP remains powered on. Furthermore, certain
memory pages (addresses > 0xc60000) are skipped even after an AMP reset.

Signed-off-by: Baojun Xu <baojun.xu@xxxxxx>
---
v2:
- Update register address from 0x07 to 7 and keep the line within the
80-character limit.‌
- ‌Remove stray/unnecessary changes.‌
- ‌Change variable type to unsigned int to comply with API requirements.‌
- ‌Replace usleep_range() with fsleep().‌
- ‌Set idle_bias_on to 0 to enable low-power mode.
- Reactivate the AMP after resume.
---
sound/soc/codecs/tas2783-sdw.c | 55 ++++++++++++++++++++--------------
1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index c217da5fccdf..8fc679d460d9 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -97,6 +97,7 @@ struct tas2783_prv {
u8 rca_binaryname[64];
u8 dev_name[32];
bool hw_init;
+ bool first_hw_init;
/* wq for firmware download */
wait_queue_head_t fw_wait;
bool fw_dl_task_done;
@@ -783,14 +784,16 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
file->version, file->length,
file->dest_addr, file->fw_data);

- ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral,
- file->dest_addr,
- file->length,
- file->fw_data);
- if (ret < 0) {
- dev_err(tas_dev->dev,
- "FW download failed: %d", ret);
- break;
+ if (!tas_dev->first_hw_init || file->dest_addr < 0xc60000) {
+ ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral,
+ file->dest_addr,
+ file->length,
+ file->fw_data);
+ if (ret < 0) {
+ dev_err(tas_dev->dev,
+ "FW download failed: %d", ret);
+ break;
+ }
}
cur_file++;
}
@@ -801,6 +804,8 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
ret = -EINVAL;
} else {
tas2783_update_calibdata(tas_dev);
+ regmap_write(tas_dev->regmap, TASDEV_REG_SDW(0, 0, 7), 0x22);
+ tas_dev->first_hw_init = true;
}

out:
@@ -940,7 +945,7 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
TAS2783_SDCA_POW_STATE_ON);
if (!ret)
break;
- usleep_range(2000, 2200);
+ fsleep(2200);
} while (retry--);
}

@@ -1038,7 +1043,7 @@ static const struct snd_soc_component_driver soc_codec_driver_tasdevice = {
.num_dapm_widgets = ARRAY_SIZE(tas_dapm_widgets),
.dapm_routes = tas_audio_map,
.num_dapm_routes = ARRAY_SIZE(tas_audio_map),
- .idle_bias_on = 1,
+ .idle_bias_on = 0,
.endianness = 1,
};

@@ -1171,25 +1176,29 @@ static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
{
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+ unsigned int val;
s32 ret;

if (tas_dev->hw_init)
return 0;

- tas_dev->fw_dl_success = false;
+ regmap_read(tas_dev->regmap, TASDEV_REG_SDW(0, 0, 7), &val);
+ /* Check if the AMP is in reset status. */
+ if (val == 0x20) {
+ tas_dev->fw_dl_success = false;

- ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
- if (ret) {
- dev_err(dev, "sw reset failed, err=%d", ret);
- return ret;
- }
- usleep_range(2000, 2200);
+ ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
+ if (ret) {
+ dev_err(dev, "sw reset failed, err=%d", ret);
+ return ret;
+ }
+ fsleep(2200);

- tas_dev->fw_use_fallback = false;
- ret = tas_fw_load(tas_dev, slave);
- if (!ret && tas_dev->fw_use_fallback)
+ tas_dev->fw_use_fallback = false;
ret = tas_fw_load(tas_dev, slave);
-
+ if (!ret && tas_dev->fw_use_fallback)
+ ret = tas_fw_load(tas_dev, slave);
+ }
if (!ret) {
if (tas_dev->sa_func_data)
ret = sdca_regmap_write_init(dev, tas_dev->regmap,
@@ -1197,7 +1206,8 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
else
ret = regmap_multi_reg_write(tas_dev->regmap, tas2783_init_seq,
ARRAY_SIZE(tas2783_init_seq));
-
+ /* Re-active AMP after resume. */
+ regmap_write(tas_dev->regmap, TASDEV_REG_SDW(0, 0, 2), 0);
if (ret)
dev_err(tas_dev->dev,
"init writes failed, err=%d", ret);
@@ -1357,6 +1367,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
tas_dev->dev = dev;
tas_dev->sdw_peripheral = peripheral;
tas_dev->hw_init = false;
+ tas_dev->first_hw_init = false;
mutex_init(&tas_dev->calib_lock);
mutex_init(&tas_dev->pde_lock);

--
2.25.1