From dc1a1b1e22066f01bb86a9b11ee998d4dc72db66 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 2 Sep 2026 09:55:58 +0200 Subject: [PATCH] ASoC: ux500: Allow repeated MSP prepare calls ALSA can call the DAI prepare callback again after an XRUN without first shutting down the stream. The MSP open helper rejects the second call with -EBUSY because the direction remains configured. Track successful playback and capture configurations at the DAI layer. Make repeated prepare calls no-ops and only close directions which were successfully prepared. Fixes: 3592b7f69a54 ("ASoC: Ux500: Add MSP I2S-driver") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260902-ux500-msp-fixes-v2-8-4b60b002d55a@kernel.org Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 28 +++++++++++++++++++++------- sound/soc/ux500/ux500_msp_dai.h | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 5b4b3126637e..37c48cc70394 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -388,15 +388,21 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, int ret; struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + unsigned int configured = is_playback ? PLAYBACK_CONFIGURED : + CAPTURE_CONFIGURED; + unsigned int dir = is_playback ? MSP_DIR_TX : MSP_DIR_RX; dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, snd_pcm_stream_str(substream)); - if (ux500_msp_i2s_close(drvdata->msp, - is_playback ? MSP_DIR_TX : MSP_DIR_RX)) { - dev_err(dai->dev, - "%s: Error: MSP %d (%s): Unable to close i2s.\n", - __func__, dai->id, snd_pcm_stream_str(substream)); + if (drvdata->configured & configured) { + if (ux500_msp_i2s_close(drvdata->msp, dir)) { + dev_err(dai->dev, + "%s: Error: MSP %d (%s): Unable to close i2s.\n", + __func__, dai->id, + snd_pcm_stream_str(substream)); + } + drvdata->configured &= ~configured; } /* Disable and unprepare clocks */ @@ -414,14 +420,20 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - int ret = 0; struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); struct snd_pcm_runtime *runtime = substream->runtime; struct ux500_msp_config msp_config; + bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int configured = is_playback ? PLAYBACK_CONFIGURED : + CAPTURE_CONFIGURED; + int ret; dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__, dai->id, snd_pcm_stream_str(substream), runtime->rate); + if (drvdata->configured & configured) + return 0; + ret = setup_msp_config(substream, dai, &msp_config); if (ret) return ret; @@ -433,7 +445,9 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, return ret; } - return ret; + drvdata->configured |= configured; + + return 0; } static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index ad4ce69bfbf5..aae582030d95 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -36,6 +36,7 @@ struct ux500_msp_i2s_drvdata { struct ux500_msp *msp; struct regulator *reg_vape; unsigned int fmt; + unsigned int configured; unsigned int tx_mask; unsigned int rx_mask; int slots;