[PATCH v4 6/7] ASoC: apple: mca: Do not mark clocks in use for non-providers
James Calligeros <[email protected]> Sat, 11 Jul 2026 11:11:24 +1000
| Newsgroups | dev.linux.lists.asahi,org.kernel.vger.linux-kernel,org.kernel.vger.linux-sound |
|---|---|
| Message-ID | <[email protected]> |
From: Hector Martin <[email protected]> On the speakers PCM, this sequence: 1. Open playback 2. Open sense 3. Close playback 4. Close sense would result in the sense FE being marked as clocks in use at (2), since there is a clock provider (playback FE). Then at (4) this would WARN since there is no driver any more when closing the in use clocks. If (1) and (2) are reversed this does not happen, since the sense PCM is not marked as using the clocks when there is no provider yet. So, check explicitly whether the substream FE is a clock provider in be_prepare, and skip everything if it isn't. Signed-off-by: Hector Martin <[email protected]> Signed-off-by: James Calligeros <[email protected]> --- sound/soc/apple/mca.c | 67 ++++++++++++++----------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index d8973e5611dd..322dd8771111 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -346,36 +346,6 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) return false; } -static int mca_be_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mca_cluster *cl = mca_dai_to_cluster(dai); - struct mca_data *mca = cl->host; - struct mca_cluster *fe_cl; - int ret; - - if (cl->port_clk_driver < 0) - return 0; - - fe_cl = &mca->clusters[cl->port_clk_driver]; - - /* - * Typically the CODECs we are paired with will require clocks - * to be present at time of unmute with the 'mute_stream' op - * or at time of DAPM widget power-up. We need to enable clocks - * here at the latest (frontend prepare would be too late). - */ - if (!mca_fe_clocks_in_use(fe_cl)) { - ret = mca_fe_enable_clocks(fe_cl); - if (ret < 0) - return ret; - } - - cl->clocks_in_use[substream->stream] = true; - - return 0; -} - static int mca_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -805,6 +775,43 @@ static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be, return fe; } +static int mca_be_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + struct mca_cluster *fe_cl, *fe_clk_cl; + int ret; + + fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); + + if (!fe_cl->clk_provider) + return 0; + + if (cl->port_clk_driver < 0) + return 0; + + fe_clk_cl = &mca->clusters[cl->port_clk_driver]; + + /* + * Typically the CODECs we are paired with will require clocks + * to be present at time of unmute with the 'mute_stream' op + * or at time of DAPM widget power-up. We need to enable clocks + * here at the latest (frontend prepare would be too late). + */ + if (!mca_fe_clocks_in_use(fe_clk_cl)) { + ret = mca_fe_enable_clocks(fe_clk_cl); + if (ret < 0) + return ret; + } + + cl->clocks_in_use[substream->stream] = true; + + return 0; +} + static int mca_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { -- 2.55.0