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: 3592b7f69a ("ASoC: Ux500: Add MSP I2S-driver")
Assisted-by: LLM
Signed-off-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260902-ux500-msp-fixes-v2-8-4b60b002d55a@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Linus Walleij 2026-09-02 09:55:58 +02:00 committed by Mark Brown
parent 7b819677b5
commit dc1a1b1e22
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 22 additions and 7 deletions

View File

@ -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,

View File

@ -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;