From f12dcaf65b9a780f0cc72e3b86479e71a59116f1 Mon Sep 17 00:00:00 2001
From: Tianling Shen <cnsztl@gmail.com>
Date: Thu, 31 Aug 2023 11:05:11 +0800
Subject: [PATCH] Revert "ASoC: fsl_sai: Refine enable/disable TE/RE sequence
 in trigger()"

This reverts commit 1b3d751045425ec38e1e68cd1d64da1856772144.
---
 sound/soc/fsl/fsl_sai.c | 126 +++++++++++++---------------------------
 1 file changed, 41 insertions(+), 85 deletions(-)

--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -37,24 +37,6 @@ static const struct snd_pcm_hw_constrain
 	.list = fsl_sai_rates,
 };
 
-/**
- * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
- *
- * SAI supports synchronous mode using bit/frame clocks of either Transmitter's
- * or Receiver's for both streams. This function is used to check if clocks of
- * the stream's are synced by the opposite stream.
- *
- * @sai: SAI context
- * @dir: stream direction
- */
-static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
-{
-	int adir = (dir == TX) ? RX : TX;
-
-	/* current dir in async mode while opposite dir in sync mode */
-	return !sai->synchronous[dir] && sai->synchronous[adir];
-}
-
 static irqreturn_t fsl_sai_isr(int irq, void *devid)
 {
 	struct fsl_sai *sai = (struct fsl_sai *)devid;
@@ -541,38 +523,6 @@ static int fsl_sai_hw_free(struct snd_pc
 	return 0;
 }
 
-static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
-{
-	unsigned int ofs = sai->soc_data->reg_offset;
-	bool tx = dir == TX;
-	u32 xcsr, count = 100;
-
-	regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
-			   FSL_SAI_CSR_TERE, 0);
-
-	/* TERE will remain set till the end of current frame */
-	do {
-		udelay(10);
-		regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr);
-	} while (--count && xcsr & FSL_SAI_CSR_TERE);
-
-	regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
-			   FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
-
-	/*
-	 * For sai master mode, after several open/close sai,
-	 * there will be no frame clock, and can't recover
-	 * anymore. Add software reset to fix this issue.
-	 * This is a hardware bug, and will be fix in the
-	 * next sai version.
-	 */
-	if (!sai->is_slave_mode) {
-		/* Software Reset */
-		regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
-		/* Clear SR bit to finish the reset */
-		regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
-	}
-}
 
 static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 		struct snd_soc_dai *cpu_dai)
@@ -581,9 +531,7 @@ static int fsl_sai_trigger(struct snd_pc
 	unsigned int ofs = sai->soc_data->reg_offset;
 
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-	int adir = tx ? RX : TX;
-	int dir = tx ? TX : RX;
-	u32 xcsr;
+	u32 xcsr, count = 100;
 
 	/*
 	 * Asynchronous mode: Clear SYNC for both Tx and Rx.
@@ -606,22 +554,10 @@ static int fsl_sai_trigger(struct snd_pc
 		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
 				   FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
 
-		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
+		regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+				   FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+		regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
 				   FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
-		/*
-		 * Enable the opposite direction for synchronous mode
-		 * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx
-		 * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx
-		 *
-		 * RM recommends to enable RE after TE for case 1 and to enable
-		 * TE after RE for case 2, but we here may not always guarantee
-		 * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables
-		 * TE after RE, which is against what RM recommends but should
-		 * be safe to do, judging by years of testing results.
-		 */
-		if (fsl_sai_dir_is_synced(sai, adir))
-			regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs),
-					   FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
 
 		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
 				   FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
@@ -636,23 +572,43 @@ static int fsl_sai_trigger(struct snd_pc
 
 		/* Check if the opposite FRDE is also disabled */
 		regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr);
-
-		/*
-		 * If opposite stream provides clocks for synchronous mode and
-		 * it is inactive, disable it before disabling the current one
-		 */
-		if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE))
-			fsl_sai_config_disable(sai, adir);
-
-		/*
-		 * Disable current stream if either of:
-		 * 1. current stream doesn't provide clocks for synchronous mode
-		 * 2. current stream provides clocks for synchronous mode but no
-		 *    more stream is active.
-		 */
-		if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE))
-			fsl_sai_config_disable(sai, dir);
-
+		if (!(xcsr & FSL_SAI_CSR_FRDE)) {
+			/* Disable both directions and reset their FIFOs */
+			regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
+					   FSL_SAI_CSR_TERE, 0);
+			regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+					   FSL_SAI_CSR_TERE, 0);
+
+			/* TERE will remain set till the end of current frame */
+			do {
+				udelay(10);
+				regmap_read(sai->regmap,
+					    FSL_SAI_xCSR(tx, ofs), &xcsr);
+			} while (--count && xcsr & FSL_SAI_CSR_TERE);
+
+			regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
+					   FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+			regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+					   FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+
+			/*
+			 * For sai master mode, after several open/close sai,
+			 * there will be no frame clock, and can't recover
+			 * anymore. Add software reset to fix this issue.
+			 * This is a hardware bug, and will be fix in the
+			 * next sai version.
+			 */
+			if (!sai->is_slave_mode) {
+				/* Software Reset for both Tx and Rx */
+				regmap_write(sai->regmap, FSL_SAI_TCSR(ofs),
+					     FSL_SAI_CSR_SR);
+				regmap_write(sai->regmap, FSL_SAI_RCSR(ofs),
+					     FSL_SAI_CSR_SR);
+				/* Clear SR bit to finish the reset */
+				regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
+				regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+			}
+		}
 		break;
 	default:
 		return -EINVAL;
