* [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag
@ 2014-03-27 11:06 Nicolin Chen
2014-03-27 13:26 ` Mark Brown
0 siblings, 1 reply; 3+ messages in thread
From: Nicolin Chen @ 2014-03-27 11:06 UTC (permalink / raw)
To: broonie, Li.Xiubo
Cc: alsa-devel, David.Laight, linuxppc-dev, linux-kernel, timur
It's quite cricial to clear error flags because SAI might hang if getting
FIFO underrun during playback (I haven't confirmed the same issue on Rx
overflow though).
So this patch enables those irq and adds isr() to clear the flags so as to
keep playback entirely safe.
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
Changelog
v2:
* Mask the active flags only for the following handler.
* Reset FIFO for FIFO underrun/overflow cases.
* Enable two error flags only as default.
* Use dev_warn for two error flags.
* Only clear those W1C bits.
sound/soc/fsl/fsl_sai.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++--
sound/soc/fsl/fsl_sai.h | 15 +++++++++
2 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index c4a4231..0bc98bb 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -23,6 +23,71 @@
#include "fsl_sai.h"
+#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+ FSL_SAI_CSR_FEIE)
+
+static irqreturn_t fsl_sai_isr(int irq, void *devid)
+{
+ struct fsl_sai *sai = (struct fsl_sai *)devid;
+ struct device *dev = &sai->pdev->dev;
+ u32 xcsr, mask;
+
+ /* Only handle those what we enabled */
+ mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
+
+ /* Tx IRQ */
+ regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
+ xcsr &= mask;
+
+ if (xcsr & FSL_SAI_CSR_WSF)
+ dev_dbg(dev, "isr: Start of Tx word detected\n");
+
+ if (xcsr & FSL_SAI_CSR_SEF)
+ dev_warn(dev, "isr: Tx Frame sync error detected\n");
+
+ if (xcsr & FSL_SAI_CSR_FEF) {
+ dev_warn(dev, "isr: Transmit underrun detected\n");
+ /* FIFO reset for safety */
+ xcsr |= FSL_SAI_CSR_FR;
+ }
+
+ if (xcsr & FSL_SAI_CSR_FWF)
+ dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
+
+ if (xcsr & FSL_SAI_CSR_FRF)
+ dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
+
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+ FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+ /* Rx IRQ */
+ regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
+ xcsr &= mask;
+
+ if (xcsr & FSL_SAI_CSR_WSF)
+ dev_dbg(dev, "isr: Start of Rx word detected\n");
+
+ if (xcsr & FSL_SAI_CSR_SEF)
+ dev_warn(dev, "isr: Rx Frame sync error detected\n");
+
+ if (xcsr & FSL_SAI_CSR_FEF) {
+ dev_warn(dev, "isr: Receive overflow detected\n");
+ /* FIFO reset for safety */
+ xcsr |= FSL_SAI_CSR_FR;
+ }
+
+ if (xcsr & FSL_SAI_CSR_FWF)
+ dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
+
+ if (xcsr & FSL_SAI_CSR_FRF)
+ dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
+
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+ FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+ return IRQ_HANDLED;
+}
+
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
@@ -373,8 +438,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
FSL_SAI_MAXBURST_TX * 2);
regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -490,12 +555,14 @@ static int fsl_sai_probe(struct platform_device *pdev)
struct fsl_sai *sai;
struct resource *res;
void __iomem *base;
- int ret;
+ int irq, ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
return -ENOMEM;
+ sai->pdev = pdev;
+
sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
if (sai->big_endian_regs)
fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -514,6 +581,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
return PTR_ERR(sai->regmap);
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+ return ret;
+ }
+
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index e432260..a264185 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -37,7 +37,21 @@
/* SAI Transmit/Recieve Control Register */
#define FSL_SAI_CSR_TERE BIT(31)
+#define FSL_SAI_CSR_FR BIT(25)
+#define FSL_SAI_CSR_xF_SHIFT 16
+#define FSL_SAI_CSR_xF_W_SHIFT 18
+#define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT)
+#define FSL_SAI_CSR_xF_W_MASK (0x7 << FSL_SAI_CSR_xF_W_SHIFT)
+#define FSL_SAI_CSR_WSF BIT(20)
+#define FSL_SAI_CSR_SEF BIT(19)
+#define FSL_SAI_CSR_FEF BIT(18)
#define FSL_SAI_CSR_FWF BIT(17)
+#define FSL_SAI_CSR_FRF BIT(16)
+#define FSL_SAI_CSR_xIE_SHIFT 8
+#define FSL_SAI_CSR_WSIE BIT(12)
+#define FSL_SAI_CSR_SEIE BIT(11)
+#define FSL_SAI_CSR_FEIE BIT(10)
+#define FSL_SAI_CSR_FWIE BIT(9)
#define FSL_SAI_CSR_FRIE BIT(8)
#define FSL_SAI_CSR_FRDE BIT(0)
@@ -99,6 +113,7 @@
#define FSL_SAI_MAXBURST_RX 6
struct fsl_sai {
+ struct platform_device *pdev;
struct regmap *regmap;
bool big_endian_regs;
--
1.8.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag
2014-03-27 11:06 [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag Nicolin Chen
@ 2014-03-27 13:26 ` Mark Brown
2014-03-28 2:41 ` Nicolin Chen
0 siblings, 1 reply; 3+ messages in thread
From: Mark Brown @ 2014-03-27 13:26 UTC (permalink / raw)
To: Nicolin Chen
Cc: alsa-devel, linux-kernel, timur, Li.Xiubo, David.Laight,
linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 1157 bytes --]
On Thu, Mar 27, 2014 at 07:06:59PM +0800, Nicolin Chen wrote:
> It's quite cricial to clear error flags because SAI might hang if getting
> FIFO underrun during playback (I haven't confirmed the same issue on Rx
> overflow though).
>
> So this patch enables those irq and adds isr() to clear the flags so as to
> keep playback entirely safe.
So, I've applied this since we're (hopefully!) very near the merge
window opening and it seems like it should be an improvement overall.
However a few things below:
> + /* Only handle those what we enabled */
> + mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
The shifting here could use a comment.
> + regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
> + FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
Using update_bits() is going to do an extra read, better to do this as:
if (xcsr)
regmap_write(sai->regmap, FSL_SAI_RCSR, xcsr);
otherwise we might be ignoring any of the bits that are actually clear
on read (it seems like there are some?).
> + return IRQ_HANDLED;
I'd expect to see IRQ_NONE if we didn't actually see an interrupt
source.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag
2014-03-27 13:26 ` Mark Brown
@ 2014-03-28 2:41 ` Nicolin Chen
0 siblings, 0 replies; 3+ messages in thread
From: Nicolin Chen @ 2014-03-28 2:41 UTC (permalink / raw)
To: Mark Brown
Cc: alsa-devel, linux-kernel, timur, Li.Xiubo, David.Laight,
linuxppc-dev
On Thu, Mar 27, 2014 at 01:26:27PM +0000, Mark Brown wrote:
> On Thu, Mar 27, 2014 at 07:06:59PM +0800, Nicolin Chen wrote:
> > It's quite cricial to clear error flags because SAI might hang if getting
> > FIFO underrun during playback (I haven't confirmed the same issue on Rx
> > overflow though).
> >
> > So this patch enables those irq and adds isr() to clear the flags so as to
> > keep playback entirely safe.
>
> So, I've applied this since we're (hopefully!) very near the merge
> window opening and it seems like it should be an improvement overall.
> However a few things below:
>
> > + /* Only handle those what we enabled */
> > + mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
>
> The shifting here could use a comment.
Will send an extra patch to cover it.
> > + regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
> > + FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
>
> Using update_bits() is going to do an extra read, better to do this as:
>
> if (xcsr)
> regmap_write(sai->regmap, FSL_SAI_RCSR, xcsr);
T/RCSR register stands for T/Rx Control (Status -- I guess) Register.
It actually contains control bits, IRQ mask bits and IRQ status bits.
Thus we can't regard it as a entire status register. That's why I try
to update it partially for status bits only at this point.
But if it's just for saving this extra read instance, I may save those
non-status bits from upper regmap_read() and then merge them into this
regmap_write() over here.
> otherwise we might be ignoring any of the bits that are actually clear
> on read (it seems like there are some?).
For all status flags bits, actually five for each, three of them are
write-1-clear and the other two are self-clearance by SAI self -- so
none of them are clear-on-read type.
> > + return IRQ_HANDLED;
>
> I'd expect to see IRQ_NONE if we didn't actually see an interrupt
> source.
Will add this.
Thank you,
Nicolin
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2014-03-28 3:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-27 11:06 [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag Nicolin Chen
2014-03-27 13:26 ` Mark Brown
2014-03-28 2:41 ` Nicolin Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).