ASoC: stm32: dfsdm: manage multiple prepare
authorOlivier Moysan <olivier.moysan@st.com>
Mon, 4 Mar 2019 14:52:43 +0000 (15:52 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 May 2019 15:54:06 +0000 (17:54 +0200)
[ Upstream commit 19441e35a43b616ea6afad91ed0d9e77268d8f6a ]

The DFSDM must be stopped when a new setting is applied.
restart systematically DFSDM on multiple prepare calls,
to apply changes.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
sound/soc/stm/stm32_adfsdm.c

index 706ff00..71d341b 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/clk.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -37,6 +38,8 @@ struct stm32_adfsdm_priv {
        /* PCM buffer */
        unsigned char *pcm_buff;
        unsigned int pos;
+
+       struct mutex lock; /* protect against race condition on iio state */
 };
 
 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
@@ -62,10 +65,12 @@ static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream,
 {
        struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
 
+       mutex_lock(&priv->lock);
        if (priv->iio_active) {
                iio_channel_stop_all_cb(priv->iio_cb);
                priv->iio_active = false;
        }
+       mutex_unlock(&priv->lock);
 }
 
 static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
@@ -74,13 +79,19 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
        struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
        int ret;
 
+       mutex_lock(&priv->lock);
+       if (priv->iio_active) {
+               iio_channel_stop_all_cb(priv->iio_cb);
+               priv->iio_active = false;
+       }
+
        ret = iio_write_channel_attribute(priv->iio_ch,
                                          substream->runtime->rate, 0,
                                          IIO_CHAN_INFO_SAMP_FREQ);
        if (ret < 0) {
                dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
                        __func__, substream->runtime->rate);
-               return ret;
+               goto out;
        }
 
        if (!priv->iio_active) {
@@ -92,6 +103,9 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
                                __func__, ret);
        }
 
+out:
+       mutex_unlock(&priv->lock);
+
        return ret;
 }
 
@@ -298,6 +312,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
 
        priv->dev = &pdev->dev;
        priv->dai_drv = stm32_adfsdm_dai;
+       mutex_init(&priv->lock);
 
        dev_set_drvdata(&pdev->dev, priv);