Devicetree
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox