@@ -37,6 +37,24 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
3737 .list = fsl_sai_rates ,
3838};
3939
40+ /**
41+ * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
42+ *
43+ * SAI supports synchronous mode using bit/frame clocks of either Transmitter's
44+ * or Receiver's for both streams. This function is used to check if clocks of
45+ * the stream's are synced by the opposite stream.
46+ *
47+ * @sai: SAI context
48+ * @dir: stream direction
49+ */
50+ static inline bool fsl_sai_dir_is_synced (struct fsl_sai * sai , int dir )
51+ {
52+ int adir = (dir == TX ) ? RX : TX ;
53+
54+ /* current dir in async mode while opposite dir in sync mode */
55+ return !sai -> synchronous [dir ] && sai -> synchronous [adir ];
56+ }
57+
4058static irqreturn_t fsl_sai_isr (int irq , void * devid )
4159{
4260 struct fsl_sai * sai = (struct fsl_sai * )devid ;
@@ -332,6 +350,8 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
332350 unsigned int ofs = sai -> soc_data -> reg_offset ;
333351 unsigned long clk_rate ;
334352 u32 savediv = 0 , ratio , savesub = freq ;
353+ int adir = tx ? RX : TX ;
354+ int dir = tx ? TX : RX ;
335355 u32 id ;
336356 int ret = 0 ;
337357
@@ -390,19 +410,17 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
390410 * 4) For Tx and Rx are both Synchronous with another SAI, we just
391411 * ignore it.
392412 */
393- if ((sai -> synchronous [TX ] && !sai -> synchronous [RX ]) ||
394- (!tx && !sai -> synchronous [RX ])) {
395- regmap_update_bits (sai -> regmap , FSL_SAI_RCR2 (ofs ),
413+ if (fsl_sai_dir_is_synced (sai , adir )) {
414+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR2 (!tx , ofs ),
396415 FSL_SAI_CR2_MSEL_MASK ,
397416 FSL_SAI_CR2_MSEL (sai -> mclk_id [tx ]));
398- regmap_update_bits (sai -> regmap , FSL_SAI_RCR2 ( ofs ),
417+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR2 (! tx , ofs ),
399418 FSL_SAI_CR2_DIV_MASK , savediv - 1 );
400- } else if ((sai -> synchronous [RX ] && !sai -> synchronous [TX ]) ||
401- (tx && !sai -> synchronous [TX ])) {
402- regmap_update_bits (sai -> regmap , FSL_SAI_TCR2 (ofs ),
419+ } else if (!sai -> synchronous [dir ]) {
420+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR2 (tx , ofs ),
403421 FSL_SAI_CR2_MSEL_MASK ,
404422 FSL_SAI_CR2_MSEL (sai -> mclk_id [tx ]));
405- regmap_update_bits (sai -> regmap , FSL_SAI_TCR2 ( ofs ),
423+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR2 ( tx , ofs ),
406424 FSL_SAI_CR2_DIV_MASK , savediv - 1 );
407425 }
408426
@@ -424,6 +442,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
424442 u32 val_cr4 = 0 , val_cr5 = 0 ;
425443 u32 slots = (channels == 1 ) ? 2 : channels ;
426444 u32 slot_width = word_width ;
445+ int adir = tx ? RX : TX ;
427446 int ret ;
428447
429448 if (sai -> slots )
@@ -470,30 +489,16 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
470489 /*
471490 * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
472491 * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
473- * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
474- * error.
492+ * RCR5(TCR5) for playback(capture), or there will be sync error.
475493 */
476494
477- if (!sai -> is_slave_mode ) {
478- if (!sai -> synchronous [TX ] && sai -> synchronous [RX ] && !tx ) {
479- regmap_update_bits (sai -> regmap , FSL_SAI_TCR4 (ofs ),
480- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK ,
481- val_cr4 );
482- regmap_update_bits (sai -> regmap , FSL_SAI_TCR5 (ofs ),
483- FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
484- FSL_SAI_CR5_FBT_MASK , val_cr5 );
485- regmap_write (sai -> regmap , FSL_SAI_TMR ,
486- ~0UL - ((1 << channels ) - 1 ));
487- } else if (!sai -> synchronous [RX ] && sai -> synchronous [TX ] && tx ) {
488- regmap_update_bits (sai -> regmap , FSL_SAI_RCR4 (ofs ),
489- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK ,
490- val_cr4 );
491- regmap_update_bits (sai -> regmap , FSL_SAI_RCR5 (ofs ),
492- FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
493- FSL_SAI_CR5_FBT_MASK , val_cr5 );
494- regmap_write (sai -> regmap , FSL_SAI_RMR ,
495- ~0UL - ((1 << channels ) - 1 ));
496- }
495+ if (!sai -> is_slave_mode && fsl_sai_dir_is_synced (sai , adir )) {
496+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR4 (!tx , ofs ),
497+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK ,
498+ val_cr4 );
499+ regmap_update_bits (sai -> regmap , FSL_SAI_xCR5 (!tx , ofs ),
500+ FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
501+ FSL_SAI_CR5_FBT_MASK , val_cr5 );
497502 }
498503
499504 regmap_update_bits (sai -> regmap , FSL_SAI_xCR4 (tx , ofs ),
@@ -522,6 +527,38 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
522527 return 0 ;
523528}
524529
530+ static void fsl_sai_config_disable (struct fsl_sai * sai , int dir )
531+ {
532+ unsigned int ofs = sai -> soc_data -> reg_offset ;
533+ bool tx = dir == TX ;
534+ u32 xcsr , count = 100 ;
535+
536+ regmap_update_bits (sai -> regmap , FSL_SAI_xCSR (tx , ofs ),
537+ FSL_SAI_CSR_TERE , 0 );
538+
539+ /* TERE will remain set till the end of current frame */
540+ do {
541+ udelay (10 );
542+ regmap_read (sai -> regmap , FSL_SAI_xCSR (tx , ofs ), & xcsr );
543+ } while (-- count && xcsr & FSL_SAI_CSR_TERE );
544+
545+ regmap_update_bits (sai -> regmap , FSL_SAI_xCSR (tx , ofs ),
546+ FSL_SAI_CSR_FR , FSL_SAI_CSR_FR );
547+
548+ /*
549+ * For sai master mode, after several open/close sai,
550+ * there will be no frame clock, and can't recover
551+ * anymore. Add software reset to fix this issue.
552+ * This is a hardware bug, and will be fix in the
553+ * next sai version.
554+ */
555+ if (!sai -> is_slave_mode ) {
556+ /* Software Reset */
557+ regmap_write (sai -> regmap , FSL_SAI_xCSR (tx , ofs ), FSL_SAI_CSR_SR );
558+ /* Clear SR bit to finish the reset */
559+ regmap_write (sai -> regmap , FSL_SAI_xCSR (tx , ofs ), 0 );
560+ }
561+ }
525562
526563static int fsl_sai_trigger (struct snd_pcm_substream * substream , int cmd ,
527564 struct snd_soc_dai * cpu_dai )
@@ -530,7 +567,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
530567 unsigned int ofs = sai -> soc_data -> reg_offset ;
531568
532569 bool tx = substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ;
533- u32 xcsr , count = 100 ;
570+ int adir = tx ? RX : TX ;
571+ int dir = tx ? TX : RX ;
572+ u32 xcsr ;
534573
535574 /*
536575 * Asynchronous mode: Clear SYNC for both Tx and Rx.
@@ -553,10 +592,22 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
553592 regmap_update_bits (sai -> regmap , FSL_SAI_xCSR (tx , ofs ),
554593 FSL_SAI_CSR_FRDE , FSL_SAI_CSR_FRDE );
555594
556- regmap_update_bits (sai -> regmap , FSL_SAI_RCSR (ofs ),
557- FSL_SAI_CSR_TERE , FSL_SAI_CSR_TERE );
558- regmap_update_bits (sai -> regmap , FSL_SAI_TCSR (ofs ),
595+ regmap_update_bits (sai -> regmap , FSL_SAI_xCSR (tx , ofs ),
559596 FSL_SAI_CSR_TERE , FSL_SAI_CSR_TERE );
597+ /*
598+ * Enable the opposite direction for synchronous mode
599+ * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx
600+ * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx
601+ *
602+ * RM recommends to enable RE after TE for case 1 and to enable
603+ * TE after RE for case 2, but we here may not always guarantee
604+ * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables
605+ * TE after RE, which is against what RM recommends but should
606+ * be safe to do, judging by years of testing results.
607+ */
608+ if (fsl_sai_dir_is_synced (sai , adir ))
609+ regmap_update_bits (sai -> regmap , FSL_SAI_xCSR ((!tx ), ofs ),
610+ FSL_SAI_CSR_TERE , FSL_SAI_CSR_TERE );
560611
561612 regmap_update_bits (sai -> regmap , FSL_SAI_xCSR (tx , ofs ),
562613 FSL_SAI_CSR_xIE_MASK , FSL_SAI_FLAGS );
@@ -571,43 +622,23 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
571622
572623 /* Check if the opposite FRDE is also disabled */
573624 regmap_read (sai -> regmap , FSL_SAI_xCSR (!tx , ofs ), & xcsr );
574- if (!(xcsr & FSL_SAI_CSR_FRDE )) {
575- /* Disable both directions and reset their FIFOs */
576- regmap_update_bits (sai -> regmap , FSL_SAI_TCSR (ofs ),
577- FSL_SAI_CSR_TERE , 0 );
578- regmap_update_bits (sai -> regmap , FSL_SAI_RCSR (ofs ),
579- FSL_SAI_CSR_TERE , 0 );
580-
581- /* TERE will remain set till the end of current frame */
582- do {
583- udelay (10 );
584- regmap_read (sai -> regmap ,
585- FSL_SAI_xCSR (tx , ofs ), & xcsr );
586- } while (-- count && xcsr & FSL_SAI_CSR_TERE );
587-
588- regmap_update_bits (sai -> regmap , FSL_SAI_TCSR (ofs ),
589- FSL_SAI_CSR_FR , FSL_SAI_CSR_FR );
590- regmap_update_bits (sai -> regmap , FSL_SAI_RCSR (ofs ),
591- FSL_SAI_CSR_FR , FSL_SAI_CSR_FR );
592-
593- /*
594- * For sai master mode, after several open/close sai,
595- * there will be no frame clock, and can't recover
596- * anymore. Add software reset to fix this issue.
597- * This is a hardware bug, and will be fix in the
598- * next sai version.
599- */
600- if (!sai -> is_slave_mode ) {
601- /* Software Reset for both Tx and Rx */
602- regmap_write (sai -> regmap , FSL_SAI_TCSR (ofs ),
603- FSL_SAI_CSR_SR );
604- regmap_write (sai -> regmap , FSL_SAI_RCSR (ofs ),
605- FSL_SAI_CSR_SR );
606- /* Clear SR bit to finish the reset */
607- regmap_write (sai -> regmap , FSL_SAI_TCSR (ofs ), 0 );
608- regmap_write (sai -> regmap , FSL_SAI_RCSR (ofs ), 0 );
609- }
610- }
625+
626+ /*
627+ * If opposite stream provides clocks for synchronous mode and
628+ * it is inactive, disable it before disabling the current one
629+ */
630+ if (fsl_sai_dir_is_synced (sai , adir ) && !(xcsr & FSL_SAI_CSR_FRDE ))
631+ fsl_sai_config_disable (sai , adir );
632+
633+ /*
634+ * Disable current stream if either of:
635+ * 1. current stream doesn't provide clocks for synchronous mode
636+ * 2. current stream provides clocks for synchronous mode but no
637+ * more stream is active.
638+ */
639+ if (!fsl_sai_dir_is_synced (sai , dir ) || !(xcsr & FSL_SAI_CSR_FRDE ))
640+ fsl_sai_config_disable (sai , dir );
641+
611642 break ;
612643 default :
613644 return - EINVAL ;
0 commit comments