Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Prasad Kumpatla" <prasad.kumpatla@oss.qualcomm.com>
Cc: robh@kernel.org, devicetree@vger.kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v2 2/2] ASoC: codecs: add Qualcomm WSA885X codec driver
Date: Wed, 01 Jul 2026 14:14:35 +0000	[thread overview]
Message-ID: <20260701141435.E93DD1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260701135913.1641328-3-prasad.kumpatla@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] The `hw_free` callback destructively resets persistent DAI configurations, breaking subsequent playback.
- [High] Calling `snd_soc_component_exit_regmap` on a devm-managed regmap causes a double free and Use-After-Free.
- [Medium] Missing state_lock acquisition in ALSA kcontrol put handlers causes data races with DAI callbacks.
- [Medium] Incomplete hardware state restoration in `mute_stream` leaves the receiver path latched in mono configuration.
- [Medium] Misleading DAI capabilities advertise unsupported sample rates.
- [Medium] Speculative missing spin-up delay after powerdown GPIO deassertion.
--

commit e15bd0da567eddb8e96d21ded36e450db91c562c
Author: Prasad Kumpatla <prasad.kumpatla@oss.qualcomm.com>

ASoC: codecs: add Qualcomm WSA885X codec driver
    
Add an ASoC codec driver for the Qualcomm WSA885X stereo smart speaker
amplifier controlled over I2C.

> diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c
> new file mode 100644
> index 0000000000000..7a3f6373f5d95
> --- /dev/null
> +++ b/sound/soc/codecs/wsa885x.c
> @@ -0,0 +1,1490 @@

[ ... ]

> +static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream,
> +				   struct snd_pcm_hw_params *params,
> +				   struct snd_soc_dai *dai)
> +{
> +	struct wsa885x_priv *wsa885x;
> +	u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx;
> +
> +	wsa885x = snd_soc_component_get_drvdata(dai->component);
> +
> +	switch (params_rate(params)) {
> +	case 8000:

[ ... ]

> +	case 352800:
> +	case 384000:
> +		pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ;
> +		cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ;
> +		cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ;
> +		break;
> +	default:
> +		dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params));
> +		return -EINVAL;
> +	}

[ ... ]

> +static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
> +{

[ ... ]

> +		if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) {
> +			regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03);
> +		} else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) {
> +			regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01);
> +		} else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) {
> +			regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02);
> +			regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, 0x01);
> +		}

[Severity: Medium]
Does this leave the hardware latched in a mono right configuration?

If the active rx_slot_mask is WSA885X_CHANNEL_MONO_RIGHT,
WSA885X_DIG_CTRL1_I2S_TDM_CH_RX is explicitly set to 0x01. If the mask is
later changed to STEREO or MONO_LEFT via kcontrol, the subsequent un-mute
operation evaluates the other branches but doesn't restore
WSA885X_DIG_CTRL1_I2S_TDM_CH_RX back to its default (0x08).

[ ... ]

> +static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream,
> +				 struct snd_soc_dai *dai)
> +{
> +	static const struct reg_sequence regs[] = {
> +		{ WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00 },
> +		{ WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00 },
> +		{ WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00 },
> +		{ WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05 },
> +		{ WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00 },
> +		{ WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00 },
> +		{ WSA885X_DIG_CTRL1_I2S_CTL0, 0x06 },
> +		{ WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, 0x08 },
> +		{ WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
> +		{ WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00 },
> +		{ WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 },
> +		{ WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 },
> +		{ WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 },
> +	};

[Severity: High]
Does clearing these registers break subsequent audio playback?

These register sequences clear persistent TDM and clock configurations like
WSA885X_DIG_CTRL0_SYS_CLK_SEL and WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE. 

Since machine drivers often invoke set_sysclk and set_tdm_slot only once
during machine initialization or startup, won't hw_free leaving the codec
without a clock source cause the next stream to fail?

[ ... ]

> +static struct snd_soc_dai_driver wsa885x_dai[] = {
> +	{
> +		.name = "wsa885x_dai_drv",
> +		.playback = {
> +			.stream_name = "WSA885X TDM Playback",
> +			.channels_min = 1,
> +			.channels_max = 2,
> +				.rates = SNDRV_PCM_RATE_8000_192000 |
> +					 SNDRV_PCM_RATE_352800 |
> +					 SNDRV_PCM_RATE_384000,

[Severity: Medium]
Does this inadvertently advertise unsupported intermediate sample rates?

SNDRV_PCM_RATE_8000_192000 includes intermediate rates like 11025Hz, 22050Hz,
and 64000Hz, but wsa885x_codec_hw_params() falls through to the default
case and returns -EINVAL for them. This can cause userspace applications to
fail abruptly when they try to negotiate formats.

[ ... ]

> +static void wsa885x_component_remove(struct snd_soc_component *component)
> +{
> +	if (!component)
> +		return;
> +
> +	snd_soc_component_exit_regmap(component);
> +}

[Severity: High]
Can this lead to a double free and use-after-free?

wsa885x->regmap is allocated via devm_regmap_init_i2c(), so devres will
automatically call regmap_exit() on device unbind. Calling
snd_soc_component_exit_regmap() here explicitly calls regmap_exit() early. 

If the sound card unbinds the ASoC component first, the regmap is freed, but
the I2C device is still bound and its IRQ handler remains active. If an
interrupt triggers, wsa885x_interrupt_handler() will access the freed regmap
resulting in a use-after-free. Later, devres will double-free the regmap
when the I2C device is actually removed.

[ ... ]

> +static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol,
> +				    struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> +	struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
> +	u32 mask = ucontrol->value.integer.value[0];
> +
> +	if (!wsa885x_is_valid_rx_slot_mask(mask))
> +		return -EINVAL;
> +
> +	if (wsa885x->rx_slot_mask == mask)
> +		return 0;
> +
> +	wsa885x->rx_slot_mask = mask;

[Severity: Medium]
Should this modification be protected by wsa885x->state_lock?

wsa885x_codec_mute_stream() evaluates rx_slot_mask multiple times in an
if-else if chain. If this kcontrol is written concurrently, mute_stream()
could see different values for rx_slot_mask during the same invocation,
potentially skipping all conditional branches and leaving
WSA885X_DIG_CTRL0_PA_FSM_CTL unconfigured.

[ ... ]

> +static int wsa885x_probe(struct i2c_client *client)
> +{

[ ... ]

> +	wsa885x->sd_n = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH);
> +	if (IS_ERR(wsa885x->sd_n))
> +		return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n),
> +							 "Shutdown Control GPIO not found\n");
> +
> +	gpiod_set_value_cansleep(wsa885x->sd_n, false);
> +
> +	ret = devm_add_action_or_reset(dev, wsa885x_gpio_powerdown, wsa885x);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n");
> +
> +	i2c_set_clientdata(client, wsa885x);
> +
> +	ret = devm_snd_soc_register_component(dev, component_driver,
> +					      wsa885x_dai,
> +					      ARRAY_SIZE(wsa885x_dai));

[Severity: Medium]
Does the codec require a stabilization delay after deasserting the shutdown
GPIO?

Hardware audio codecs typically need a short delay (e.g. 5-20ms) after
coming out of hard reset before their internal digital logic can acknowledge
I2C traffic. Since wsa885x_component_probe() will issue I2C commands
immediately upon component registration via wsa885x_hw_init(), could this
lead to I2C NACKs or timeouts on some platforms?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701135913.1641328-1-prasad.kumpatla@oss.qualcomm.com?part=2

      reply	other threads:[~2026-07-01 14:14 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01 13:59 [PATCH v2 0/2] ASoC: add Qualcomm WSA885X codec support Prasad Kumpatla
2026-07-01 13:59 ` [PATCH v2 1/2] dt-bindings: sound: add WSA8855 bindings Prasad Kumpatla
2026-07-01 16:39   ` Rob Herring (Arm)
2026-07-01 13:59 ` [PATCH v2 2/2] ASoC: codecs: add Qualcomm WSA885X codec driver Prasad Kumpatla
2026-07-01 14:14   ` sashiko-bot [this message]

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=20260701141435.E93DD1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=prasad.kumpatla@oss.qualcomm.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