Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp148316pxa; Tue, 4 Aug 2020 19:32:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJybvmIXSl8e0bz9FfMaCaktd5N+664PohXiciosDTTdL/PPl/BUz+T8sKAL33sSSQUhGeGG X-Received: by 2002:aa7:ccc1:: with SMTP id y1mr796121edt.317.1596594755928; Tue, 04 Aug 2020 19:32:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1596594755; cv=none; d=google.com; s=arc-20160816; b=dmZ4pDZ5LSvtt1pmkOhYvb8ffJdJuO0dcQpvoZ0O4uVyMe1xy4n11YpvUs+r6SREbE XgxiI25MxSBuJUHWTmox4lmWVb03B0b9OBWr4C1/bz7b3pEqQfUihvNVxpGc3OlIMH1f HN2xUi3Q3dOUdbxoTjQEWTNGS6gPZDiX/uek24cGTSdt8ZqJ7Dh0Us0JB6TMY8rcOtFj e9+tkVzoU9pUQb+6+kx9GptBgKO/IoVhaOPDRVJ2CqOwO2EbuoMwLnGB9kPfDE0jsWM2 ziB8VE9B5m4cuwKTnxUZt1CgWiR4oGPviK2ZUKSO/q8UvfhP/Og4/kEpnRmo/HGt6IyG fH1g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:to:from; bh=RJGfdNy6U3iqoxzL1zWT372PMbQ4wDSy6Ahz1gMV+QE=; b=DwImFiogtSQj+VoaqMSQR/O5E4ddZziHNyMimLP46FQAITq6oqaM2mzj1SsI547S0r AeSnhvULGpctZPXiOdc5i3WRLq7nFdegS8MLJllm7GLJyunvbiJvbmG88OM6ADcx/TtH avlLhOimrdRB+fwJRDK4/ihN2lyC1f5/4nTi/b7OaTMXYf+C2CA7j58k8gQlYr6oUuaz imye7se9Cdt4mMkt1kYqgDKT69eWHZoxCVqrDd+zSk/0dZfNma2I1twTkQ6Pcd4e33P6 2ZPyxKKsKszETQhk0UvRypuQcVVoMNlXuXQD75kx25xFKm5+9lc5J509BBAOO01BRojG xB5w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c6si418432ejr.345.2020.08.04.19.32.13; Tue, 04 Aug 2020 19:32:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727008AbgHEC2m (ORCPT + 99 others); Tue, 4 Aug 2020 22:28:42 -0400 Received: from inva021.nxp.com ([92.121.34.21]:46322 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726915AbgHEC2i (ORCPT ); Tue, 4 Aug 2020 22:28:38 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 257AD20138C; Wed, 5 Aug 2020 04:28:37 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 4741320019A; Wed, 5 Aug 2020 04:28:32 +0200 (CEST) Received: from 10.192.242.69 (shlinux2.ap.freescale.net [10.192.224.44]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 5AF1640302; Wed, 5 Aug 2020 04:28:26 +0200 (CEST) From: Shengjiu Wang To: timur@kernel.org, nicoleotsuka@gmail.com, Xiubo.Lee@gmail.com, festevam@gmail.com, lgirdwood@gmail.com, broonie@kernel.org, perex@perex.cz, tiwai@suse.com, alsa-devel@alsa-project.org, linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] ASoC: fsl_sai: Refine enable and disable sequence for synchronous mode Date: Wed, 5 Aug 2020 10:23:53 +0800 Message-Id: <1596594233-13489-3-git-send-email-shengjiu.wang@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1596594233-13489-1-git-send-email-shengjiu.wang@nxp.com> References: <1596594233-13489-1-git-send-email-shengjiu.wang@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Tx synchronous with Rx: The TCSR.TE is no need to enabled when only Rx is going to be enabled. Check if need to disable RSCR.RE before disabling TCSR.TE. Rx synchronous with Tx: The RCSR.RE is no need to enabled when only Tx is going to be enabled. Check if need to disable TSCR.RE before disabling RCSR.TE. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_sai.c | 126 +++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 41 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 84714fe7144c..f30c4e7b5221 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -517,6 +517,56 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, return 0; } +/** + * 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 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) @@ -525,7 +575,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 xcsr, count = 100; + int adir = tx ? RX : TX; + int dir = tx ? TX : RX; + u32 xcsr; /* * Asynchronous mode: Clear SYNC for both Tx and Rx. @@ -548,10 +600,22 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, 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_RCSR(ofs), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, 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); @@ -566,43 +630,23 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, /* Check if the opposite FRDE is also disabled */ regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); - 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); - } - } + + /* + * 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); + break; default: return -EINVAL; -- 2.27.0