Skip to content

Commit 6223637

Browse files
JihedChaibibroonie
authored andcommitted
ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on failure
ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in sequence (mclk, sclk, lrclk) without checking the return value of any of them. If an intermediate enable fails, the clocks that were already enabled are never rolled back, leaking them until the next disable cycle — which may never come if the stream never started cleanly. Change ep93xx_i2s_enable() from void to int. Add error checking after each clk_prepare_enable() call and unwind already-enabled clocks on failure. Propagate the error through ep93xx_i2s_startup() and ep93xx_i2s_resume(), both of which already return int. Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com> Fixes: f4ff6b5 ("ASoC: cirrus: i2s: Prepare clock before using it") Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent b9eff97 commit 6223637

1 file changed

Lines changed: 24 additions & 10 deletions

File tree

sound/soc/cirrus/ep93xx-i2s.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
9191
return __raw_readl(info->regs + reg);
9292
}
9393

94-
static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
94+
static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
9595
{
9696
unsigned base_reg;
97+
int err;
9798

9899
if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
99100
(ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
100101
/* Enable clocks */
101-
clk_prepare_enable(info->mclk);
102-
clk_prepare_enable(info->sclk);
103-
clk_prepare_enable(info->lrclk);
102+
err = clk_prepare_enable(info->mclk);
103+
if (err)
104+
return err;
105+
err = clk_prepare_enable(info->sclk);
106+
if (err) {
107+
clk_disable_unprepare(info->mclk);
108+
return err;
109+
}
110+
err = clk_prepare_enable(info->lrclk);
111+
if (err) {
112+
clk_disable_unprepare(info->sclk);
113+
clk_disable_unprepare(info->mclk);
114+
return err;
115+
}
104116

105117
/* Enable i2s */
106118
ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
@@ -119,6 +131,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
119131
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
120132
EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
121133
EP93XX_I2S_TXCTRL_TXUFIE);
134+
135+
return 0;
122136
}
123137

124138
static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
@@ -195,9 +209,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
195209
{
196210
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
197211

198-
ep93xx_i2s_enable(info, substream->stream);
199-
200-
return 0;
212+
return ep93xx_i2s_enable(info, substream->stream);
201213
}
202214

203215
static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
@@ -373,14 +385,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
373385
static int ep93xx_i2s_resume(struct snd_soc_component *component)
374386
{
375387
struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
388+
int err;
376389

377390
if (!snd_soc_component_active(component))
378391
return 0;
379392

380-
ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
381-
ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
393+
err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
394+
if (err)
395+
return err;
382396

383-
return 0;
397+
return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
384398
}
385399
#else
386400
#define ep93xx_i2s_suspend NULL

0 commit comments

Comments
 (0)