Skip to content

Commit bf66f14

Browse files
committed
Merge series "refine and clean code for synchronous mode" from Shengjiu Wang <shengjiu.wang@nxp.com>:
refine and clean code for synchronous mode Shengjiu Wang (3): ASoC: fsl_sai: Refine enable/disable TE/RE sequence in trigger() ASoC: fsl_sai: Drop TMR/RMR settings for synchronous mode ASoC: fsl_sai: Replace synchronous check with fsl_sai_dir_is_synced changes in v3: - Add reviewed-by Nicolin - refine the commit log. - Add one more patch #3 changes in v2: - Split the commit - refine the sequence in trigger stop sound/soc/fsl/fsl_sai.c | 173 +++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 71 deletions(-) -- 2.27.0
2 parents cba62c8 + 9355a7b commit bf66f14

File tree

1 file changed

+102
-71
lines changed

1 file changed

+102
-71
lines changed

sound/soc/fsl/fsl_sai.c

Lines changed: 102 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
4058
static 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

526563
static 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

Comments
 (0)