ASoC: stm32: spdifrx: retry synchronization in sync state
authorOlivier Moysan <olivier.moysan@st.com>
Fri, 11 Oct 2019 08:48:16 +0000 (10:48 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 14 Oct 2019 11:57:29 +0000 (12:57 +0100)
When STM32 SPDIFRX is in sync state, allow multiple
synchro attempts, instead of exiting on first unsuccessful
trial. This is useful when spdif signal is not immediately
available on input. This also allows Pulseaudio to check
iec capture device availability when no signal is present.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Link: https://lore.kernel.org/r/20191011084816.14279-1-olivier.moysan@st.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/stm/stm32_spdifrx.c

index cd4b235..3fd28ee 100644 (file)
@@ -351,6 +351,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
                     SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO;
                cr_mask = cr;
 
+               cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63);
+               cr_mask |= SPDIFRX_CR_NBTR_MASK;
                cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC);
                cr_mask |= SPDIFRX_CR_SPDIFEN_MASK;
                ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
@@ -666,7 +668,7 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
        struct snd_pcm_substream *substream = spdifrx->substream;
        struct platform_device *pdev = spdifrx->pdev;
        unsigned int cr, mask, sr, imr;
-       unsigned int flags;
+       unsigned int flags, sync_state;
        int err = 0, err_xrun = 0;
 
        regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr);
@@ -726,11 +728,23 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
        }
 
        if (err) {
-               /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */
+               regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr);
+               sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) &&
+                            SPDIFRX_SPDIFEN_SYNC;
+
+               /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */
                cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE);
                regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
                                   SPDIFRX_CR_SPDIFEN_MASK, cr);
 
+               /* If SPDIFRX was in STATE_SYNC, retry synchro */
+               if (sync_state) {
+                       cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC);
+                       regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
+                                          SPDIFRX_CR_SPDIFEN_MASK, cr);
+                       return IRQ_HANDLED;
+               }
+
                if (substream)
                        snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);