Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp488786ybi; Tue, 2 Jul 2019 23:52:38 -0700 (PDT) X-Google-Smtp-Source: APXvYqznuUfwDC5erKemXXd/1LlmxL6CWTZOlJzqmh6vABqq0CVn1tW7HKap53Ihnq9DfuIhPufK X-Received: by 2002:a17:902:bb90:: with SMTP id m16mr38169324pls.54.1562136758043; Tue, 02 Jul 2019 23:52:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562136758; cv=none; d=google.com; s=arc-20160816; b=tB5gfrkBCrM1sgdCaSQeAu/LbcslYJTptZo+ei0pU/LpQaUNRjAk6bvn9d4ZlZZVPQ mZUfYOL5e7pD1+5tLqer+zoqxpr70Zpfcy8cfAxCMi/V6B1J51ZOGiSYAwiQ8WWn8z32 auA3WvzgKjEhHZFg8QQ4maDcd5tanPI8Y99SRufxYEOq/yqsusUCID9UMjcrc9gJstwO 76n/pkGpCamYxXpmtfoLL2h7G6OGu27+O/jZm7P9orVpWKwETI+WceaXLxWSVjvz/8xS mx4qNzkwAGVKz0oM7psfgM2GvOUVg+faGW/6MxITyI20VagRlk4s0zMZT5+fEuF5+eMd ta9g== 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:references :in-reply-to:message-id:date:subject:cc:to:from; bh=YT5NQZ1YzShh/P4BINlpyvbMMvJfKPR3uy/TU7bl8sw=; b=xlxdLYM3bq4iCqFg6ddP5XCNvsBov1E+xNGj3NYh5vsu4fz3J9LC+1mBwCuhXJcOKH zIcxkhUmcA7ErFygRl2E68v7BeG8edJoxYdGwCTZqJTIXxNZ7FjDunSNviKCdp1rDRxG BmB51GO6mGOHiO48xgdrH+j4qQFsVhI3CaF0vDdZ7V2hJ3AiHyMGQlrp4JQPOrG7Nyhz A56ATGo4Oq/77n6GTjbR6JGHvQeYIDFOFFQtc8fzFVgXqbml+eKK2m0o/hTbCfT7pVPw B3mJTw40GREJZC3EgO/pA232Omheozr0i1N9EbPkdOpD60lBtVC/hzjydzGHWRUdJIPP yEPg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 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. [209.132.180.67]) by mx.google.com with ESMTP id v62si1436791pgv.126.2019.07.02.23.52.22; Tue, 02 Jul 2019 23:52:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 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 S1727174AbfGCGvZ (ORCPT + 99 others); Wed, 3 Jul 2019 02:51:25 -0400 Received: from inva021.nxp.com ([92.121.34.21]:39342 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726236AbfGCGvV (ORCPT ); Wed, 3 Jul 2019 02:51:21 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id ACEC2200351; Wed, 3 Jul 2019 08:51:18 +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 19643200349; Wed, 3 Jul 2019 08:51:14 +0200 (CEST) Received: from titan.ap.freescale.net (TITAN.ap.freescale.net [10.192.208.233]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id DED2D402EB; Wed, 3 Jul 2019 14:51:08 +0800 (SGT) From: shengjiu.wang@nxp.com To: timur@kernel.org, nicoleotsuka@gmail.com, Xiubo.Lee@gmail.com, festevam@gmail.com, broonie@kernel.org, alsa-devel@alsa-project.org Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 2/2] ASoC: fsl_esai: recover the channel swap after xrun Date: Wed, 3 Jul 2019 14:42:05 +0800 Message-Id: X-Mailer: git-send-email 2.14.1 In-Reply-To: References: In-Reply-To: References: 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 From: Shengjiu Wang There is chip errata ERR008000, the reference doc is (https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf), The issue is "While using ESAI transmit or receive and an underrun/overrun happens, channel swap may occur. The only recovery mechanism is to reset the ESAI." This issue exist in imx3/imx5/imx6(partial) series. In this commit add a tasklet to handle reset of ESAI after xrun happens to recover the channel swap. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_esai.c | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 20039ae9893b..8c92e49ad6d8 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -32,6 +32,7 @@ * @extalclk: esai clock source to derive HCK, SCK and FS * @fsysclk: system clock source to derive HCK, SCK and FS * @spbaclk: SPBA clock (optional, depending on SoC design) + * @task: tasklet to handle the reset operation * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots @@ -42,6 +43,7 @@ * @sck_div: if using PSR/PM dividers for SCKx clock * @slave_mode: if fully using DAI slave mode * @synchronous: if using tx/rx synchronous mode + * @reset_at_xrun: flags for enable reset operaton * @name: driver name */ struct fsl_esai { @@ -53,6 +55,7 @@ struct fsl_esai { struct clk *extalclk; struct clk *fsysclk; struct clk *spbaclk; + struct tasklet_struct task; u32 fifo_depth; u32 slot_width; u32 slots; @@ -65,6 +68,7 @@ struct fsl_esai { bool sck_div[2]; bool slave_mode; bool synchronous; + bool reset_at_xrun; char name[32]; }; @@ -73,8 +77,16 @@ static irqreturn_t esai_isr(int irq, void *devid) struct fsl_esai *esai_priv = (struct fsl_esai *)devid; struct platform_device *pdev = esai_priv->pdev; u32 esr; + u32 saisr; regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr); + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); + + if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE)) && + esai_priv->reset_at_xrun) { + dev_dbg(&pdev->dev, "reset module for xrun\n"); + tasklet_schedule(&esai_priv->task); + } if (esr & ESAI_ESR_TINIT_MASK) dev_dbg(&pdev->dev, "isr: Transmission Initialized\n"); @@ -634,10 +646,17 @@ static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx) ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); + + /* Enable Exception interrupt */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, ESAI_xCR_xEIE); } static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) { + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), @@ -652,6 +671,53 @@ static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) ESAI_xFCR_xFR, 0); } +static void fsl_esai_reset(unsigned long arg) +{ + struct fsl_esai *esai_priv = (struct fsl_esai *)arg; + u32 saisr, tfcr, rfcr; + + /* save the registers */ + regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); + regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); + + /* stop the tx & rx */ + fsl_esai_trigger_stop(esai_priv, 1); + fsl_esai_trigger_stop(esai_priv, 0); + + /* reset the esai, and restore the registers */ + fsl_esai_init(esai_priv); + + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, + ESAI_xCR_xPR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, + ESAI_xCR_xPR); + + /* restore registers by regcache_sync */ + fsl_esai_register_restore(esai_priv); + + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, 0); + + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, + ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, + ESAI_PCRC_PC(ESAI_GPIO)); + + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); + + /* restart tx / rx, if they already enabled */ + if (tfcr & ESAI_xFCR_xFEN) + fsl_esai_trigger_start(esai_priv, 1); + if (rfcr & ESAI_xFCR_xFEN) + fsl_esai_trigger_start(esai_priv, 0); +} + static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -856,6 +922,10 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np); + if (of_device_is_compatible(np, "fsl,vf610-esai") || + of_device_is_compatible(np, "fsl,imx35-esai")) + esai_priv->reset_at_xrun = true; + /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); @@ -955,6 +1025,9 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + tasklet_init(&esai_priv->task, fsl_esai_reset, + (unsigned long)esai_priv); + pm_runtime_enable(&pdev->dev); regcache_cache_only(esai_priv->regmap, true); @@ -968,7 +1041,10 @@ static int fsl_esai_probe(struct platform_device *pdev) static int fsl_esai_remove(struct platform_device *pdev) { + struct fsl_esai *esai_priv = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); + tasklet_kill(&esai_priv->task); return 0; } -- 2.21.0