Skip to content

Commit ff66736

Browse files
TE-N-ShengjiuWangDong Aisheng
authored andcommitted
ASoC: fsl_esai: Add spin lock to protect reset, stop and start
xrun may happen at the end of stream, the trigger->fsl_esai_trigger_stop maybe called in the middle of fsl_esai_hw_reset, this may cause esai in wrong state after stop, and there may be endless xrun interrupt. This issue may also happen with trigger->fsl_esai_trigger_start. So Add spin lock to lock those functions. Fixes: 7ccafa2 ("ASoC: fsl_esai: recover the channel swap after xrun") Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Acked-by: Nicolin Chen <nicoleotsuka@gmail.com> Link: https://lore.kernel.org/r/52e92c4221a83e39a84a6cd92fc3d5479b44894c.1572252321.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 5311581 commit ff66736

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

sound/soc/fsl/fsl_esai.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* @fsysclk: system clock source to derive HCK, SCK and FS
3535
* @spbaclk: SPBA clock (optional, depending on SoC design)
3636
* @task: tasklet to handle the reset operation
37+
* @lock: spin lock between hw_reset() and trigger()
3738
* @fifo_depth: depth of tx/rx FIFO
3839
* @slot_width: width of each DAI slot
3940
* @slots: number of slots
@@ -57,6 +58,7 @@ struct fsl_esai {
5758
struct clk *fsysclk;
5859
struct clk *spbaclk;
5960
struct tasklet_struct task;
61+
spinlock_t lock; /* Protect hw_reset and trigger */
6062
u32 fifo_depth;
6163
u32 slot_width;
6264
u32 slots;
@@ -704,8 +706,10 @@ static void fsl_esai_hw_reset(unsigned long arg)
704706
{
705707
struct fsl_esai *esai_priv = (struct fsl_esai *)arg;
706708
bool tx = true, rx = false, enabled[2];
709+
unsigned long lock_flags;
707710
u32 tfcr, rfcr;
708711

712+
spin_lock_irqsave(&esai_priv->lock, lock_flags);
709713
/* Save the registers */
710714
regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);
711715
regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);
@@ -743,26 +747,33 @@ static void fsl_esai_hw_reset(unsigned long arg)
743747
fsl_esai_trigger_start(esai_priv, tx);
744748
if (enabled[rx])
745749
fsl_esai_trigger_start(esai_priv, rx);
750+
751+
spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
746752
}
747753

748754
static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
749755
struct snd_soc_dai *dai)
750756
{
751757
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
752758
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
759+
unsigned long lock_flags;
753760

754761
esai_priv->channels[tx] = substream->runtime->channels;
755762

756763
switch (cmd) {
757764
case SNDRV_PCM_TRIGGER_START:
758765
case SNDRV_PCM_TRIGGER_RESUME:
759766
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
767+
spin_lock_irqsave(&esai_priv->lock, lock_flags);
760768
fsl_esai_trigger_start(esai_priv, tx);
769+
spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
761770
break;
762771
case SNDRV_PCM_TRIGGER_SUSPEND:
763772
case SNDRV_PCM_TRIGGER_STOP:
764773
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
774+
spin_lock_irqsave(&esai_priv->lock, lock_flags);
765775
fsl_esai_trigger_stop(esai_priv, tx);
776+
spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
766777
break;
767778
default:
768779
return -EINVAL;
@@ -1065,6 +1076,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
10651076

10661077
dev_set_drvdata(&pdev->dev, esai_priv);
10671078

1079+
spin_lock_init(&esai_priv->lock);
10681080
ret = fsl_esai_hw_init(esai_priv);
10691081
if (ret)
10701082
return ret;

0 commit comments

Comments
 (0)