ASoC: qcom: q6apm-lpass-dais: start the graph at prepare

The DAPM power-up sequence runs during snd_pcm prepare, but the BE
port graph is only started at trigger time. A codec that powers up
synchronously from a DAPM widget event and needs a running bit clock
at that point - such as aw88261 since commit caea99ac809d ("ASoC:
codecs: aw88261: remove async start") - can therefore never see a
live clock: its power-up check runs before the trigger and fails on
every stream start.

Start the graph at the end of prepare instead, mirroring what
q6afe_dai_prepare() does on the legacy stack, so the interface
clocks already run when DAPM powers up the codec. The FE side
already starts its own graph at prepare in q6apm_dai_prepare();
only the BE waited for trigger. The trigger-time start is kept as
a fallback, guarded by is_port_started.

Tested on the Fairphone (Gen. 6) - 2x aw88261 on Senary MI2S:
without this the amplifiers fail to power up with SYSST reporting
"no clock" on every stream start; with it they start synchronously,
including for the first short stream of the boot.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
This commit is contained in:
Jorijn van der Graaf 2026-07-05 21:32:11 +02:00
commit d571dd42d3

View file

@ -224,6 +224,21 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
dev_err(dai->dev, "Failed to prepare Graph %d\n", rc);
goto err;
}
/*
* Start the port already at prepare, like q6afe does: this starts
* the interface clocks before the DAPM power-up sequence runs, so
* codecs that need a live BCLK at power-up (e.g. aw88261) can
* start synchronously. The trigger callback keeps its start as a
* no-op fallback via is_port_started.
*/
rc = q6apm_graph_start(dai_data->graph[dai->id]);
if (rc < 0) {
dev_err(dai->dev, "Failed to start APM port %d\n", dai->id);
goto err;
}
dai_data->is_port_started[dai->id] = true;
return 0;
err:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {