From: sashiko-bot@kernel.org
To: "Gianluca Boiano" <morf3089@gmail.com>
Cc: devicetree@vger.kernel.org, conor+dt@kernel.org, robh@kernel.org
Subject: Re: [PATCH v1 2/2] ASoC: codecs: add TAS2557 mono smart amplifier driver
Date: Thu, 09 Jul 2026 22:26:59 +0000 [thread overview]
Message-ID: <20260709222659.721A11F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260709221331.989109-3-morf3089@gmail.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] The failsafe recovery path resets the hardware but completely fails to restore dynamic runtime configurations (DAC gain, ASI offsets, I/V sense slots).
- [High] TDM slot configurations and RX/TX offsets are ignored and overwritten by `hw_params` and flawed static calculations, rendering `snd_soc_dai_set_tdm_slot()` ineffective and corrupting audio on the right channel.
- [High] DAI format configuration from `set_dai_fmt()` is permanently wiped out by hardcoded startup data upon device enable.
- [High] Use-after-free of the `tas2557->fw_done` completion structure during driver unbind.
- [High] Capture-only streams are permanently muted, and concurrent capture streams are broken when a playback stream stops.
- [Medium] The `ISENSE Switch` and `VSENSE Switch` ALSA controls are unconditionally forcefully overridden by hardcoded values during stream power-up.
- [Medium] Race condition between asynchronous firmware loading and DAPM stream start, causing random playback failures.
--
--- Patch [2]: [PATCH v1 2/2] ASoC: codecs: add TAS2557 mono smart amplifier driver ---
commit e815fd708cfa73cfc0683782f9e776870209a100
Author: Gianluca Boiano <morf3089@gmail.com>
ASoC: codecs: add TAS2557 mono smart amplifier driver
The TAS2557 is a mono Class-D smart amplifier with an on-chip DSP. This
commit adds the driver for the device, including firmware loading, power
management, ALSA controls, and IRQ-based fault recovery.
> diff --git a/sound/soc/codecs/tas2557.c b/sound/soc/codecs/tas2557.c
> index 0000000000000..08ab437b63091
> --- /dev/null
> +++ b/sound/soc/codecs/tas2557.c
[ ... ]
> @@ -191,24 +191,20 @@
> static const unsigned int tas2557_startup_data[] = {
> TAS2557_GPI_PIN_REG, 0x15, /* enable DIN, MCLK, CCI */
> TAS2557_GPIO1_PIN_REG, 0x01, /* enable BCLK (ASI1) */
> TAS2557_GPIO2_PIN_REG, 0x01, /* enable WCLK (ASI1) */
> /* ASI2 GPIO wiring; arm the BCLK source (GPIO5) before its dividers */
> TAS2557_GPIO6_PIN_REG, 0x01, /* GPIO6 = ASI2 WCLK input */
> TAS2557_GPIO8_PIN_REG, 0x02, /* GPIO8 = ASI2 DIN */
> TAS2557_GPIO5_PIN_REG, 0x01, /* GPIO5 = ASI2 BCLK input */
> TAS2557_ASI2_DAC_FORMAT_REG, 0x18, /* ASI2: 32-bit I2S */
[Severity: High]
Does this hardcoded startup sequence permanently override the custom DAI
format?
Any custom format set earlier via set_dai_fmt() to the
TAS2557_ASIx_DAC_FORMAT_REG register appears to be erased on stream start
when tas2557_startup_data unconditionally writes 0x18 (32-bit I2S).
> TAS2557_ASI2_BDIV_CLK_SEL_REG, 0x01,
> TAS2557_ASI2_BDIV_CLK_RATIO_REG, 0x01,
> TAS2557_ASI2_BDIV_CLK_RATIO_REG, 0x81, /* power up BDIV */
> TAS2557_ASI2_WDIV_CLK_RATIO_REG, 0x40,
> TAS2557_ASI2_WDIV_CLK_RATIO_REG, 0xc0, /* power up WDIV */
> TAS2557_GPIO7_PIN_REG, 0x15, /* GPIO7 = ASI2 DOUT */
> /* Power sequencing: Class-D + Boost first, then DSP/PLL */
> TAS2557_POWER_CTRL2_REG, 0xA0, /* Class-D, Boost power up */
> TAS2557_POWER_CTRL2_REG, 0xA3, /* Class-D, Boost, IV-sense power up */
[Severity: Medium]
Could this hardcoded startup data silently override the ALSA mixer controls?
Writing 0xA3 unconditionally activates both ISENSE and VSENSE whenever
a stream powers up, ignoring any user preferences previously cached by the
ISENSE and VSENSE ALSA switches.
> TAS2557_POWER_CTRL1_REG, 0xF8, /* PLL, DSP, clock dividers power up */
> TAS2557_UDELAY, 2000, /* 2 ms stabilisation */
> TAS2557_CLK_ERR_CTRL, 0x2b, /* enable clock error detection */
[ ... ]
> @@ -1334,14 +1334,10 @@
> done:
> complete(&tas2557->fw_done);
> }
[Severity: High]
Can this completion sequence lead to a use-after-free during driver unbind?
If tas2557_fw_ready() completes fw_done outside the protection of
tas2557->lock:
tas2557_fw_ready():
mutex_unlock(&tas2557->lock);
complete(&tas2557->fw_done);
A concurrent unbind thread waking up in tas2557_fw_teardown() could acquire
the mutex, free the driver state, and exit. Devres would then free the
tas2557 allocation while complete() is still attempting to release the
wait-queue spinlock inside the freed memory.
> static void tas2557_fw_teardown(void *data)
> {
> struct tas2557_priv *tas2557 = data;
>
> if (tas2557->fw_requested)
> wait_for_completion(&tas2557->fw_done);
>
> mutex_lock(&tas2557->lock);
[ ... ]
> @@ -1520,11 +1520,7 @@
> tas2557_hw_reset(tas2557);
>
> ret = tas2557_load_data(tas2557, tas2557_default_data);
> if (ret < 0)
> return ret;
>
> if (tas2557->fw) {
[Severity: High]
Does this recovery path miss restoring the dynamic runtime configurations?
After performing a hardware reset and reloading default data, this
sequence appears to skip re-applying the runtime states established in
tas2557_enable().
Missing the restoration of SPK_CTRL_REG, SNS_CTRL_REG, and ASI offset
registers could leave the device at its default maximum volume (0 dB)
and break both TDM routing and I/V capture routing until a full stream
restart.
> ret = tas2557_set_program(tas2557, tas2557->current_program,
> (int)tas2557->current_config);
> if (ret < 0)
> return ret;
> }
[ ... ]
> @@ -1621,9 +1621,6 @@
> if (enable && !tas2557->powered) {
> if (!tas2557->fw) {
> dev_warn(tas2557->dev,
> "firmware not loaded, cannot produce audio; install %s\n",
> tas2557->fw_name[0] ? tas2557->fw_name
> : TAS2557_FW_NAME);
> return -ENODEV;
> }
[Severity: Medium]
Is there a race condition here if a stream starts before the async firmware
load completes?
Since request_firmware_nowait() is used in probe without blocking
component registration, a fast userspace audio request could reach
tas2557_enable() while tas2557->fw is still NULL, causing the stream
to forcefully fail with -ENODEV instead of deferring.
>
> /*
> * Re-apply firmware program + config for the current sample
[ ... ]
> @@ -1685,7 +1685,4 @@
> if (tas2557->muted) {
> ret = tas2557_clk_err_detect(tas2557, false);
> } else {
> ret = tas2557_load_data(tas2557, tas2557_unmute_data);
> if (ret >= 0)
> ret = tas2557_clk_err_detect(tas2557, true);
> }
[Severity: High]
Are capture-only streams permanently muted by this design?
Because .no_capture_mute = 1 is set in tas2557_dai_ops, the ASoC core
skips calling tas2557_mute_stream(0) when a capture stream starts.
Because tas2557->muted is initialized to true, tas2557_enable() will
skip the unmute sequence here, keeping the capture paths completely
silent.
Furthermore, if a concurrent playback stream halts, tas2557_mute_stream()
unconditionally writes 0x03 to TAS2557_MUTE_REG, which breaks the ongoing
capture stream by hard-muting all paths.
> if (ret < 0)
> return ret;
[ ... ]
> @@ -1753,8 +1753,5 @@
> width = tas2557->tdm_slot_width > 0 ? tas2557->tdm_slot_width :
> params_physical_width(params);
> offset = (tas2557->channel == 0) ? 1 : 1 + width * 2;
> tas2557->asi_offset = offset;
>
[Severity: High]
Will this static calculation overwrite offsets configured by set_tdm_slot()?
When tas2557_hw_params() unconditionally resets tas2557->asi_offset,
any custom RX offset requested by machine drivers is lost.
Additionally, since tas2557_enable() only restores TAS2557_ASIx_OFFSET1_REG
(RX) and completely omits restoring TAS2557_ASIx_OFFSET2_REG (TX),
the capture offsets seem to be permanently lost after a device reset.
> /* Playback runs over ASI2; ASI1 is programmed too (per TI driver) */
> ret = tas2557_dev_write(tas2557, TAS2557_ASI2_OFFSET1_REG, offset);
> if (ret < 0)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709221331.989109-1-morf3089@gmail.com?part=2
next prev parent reply other threads:[~2026-07-09 22:26 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 22:13 [PATCH v1 0/2] ASoC: codecs: add Texas Instruments TAS2557 smart amplifier driver Gianluca Boiano
2026-07-09 22:13 ` [PATCH v1 1/2] dt-bindings: sound: add Texas Instruments TAS2557 Gianluca Boiano
2026-07-10 4:10 ` Wang, Sen
2026-07-11 11:39 ` Gianluca Boiano
2026-07-10 12:49 ` Mark Brown
2026-07-11 11:39 ` Gianluca Boiano
2026-07-09 22:13 ` [PATCH v1 2/2] ASoC: codecs: add TAS2557 mono smart amplifier driver Gianluca Boiano
2026-07-09 22:26 ` sashiko-bot [this message]
2026-07-10 4:40 ` Wang, Sen
2026-07-10 12:45 ` Mark Brown
2026-07-11 11:39 ` Gianluca Boiano
2026-07-10 13:55 ` Mark Brown
2026-07-11 11:40 ` Gianluca Boiano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260709222659.721A11F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=morf3089@gmail.com \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.