From 4355082149429d1f87b6fbfc3ebc6305a5372ce2 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Tue, 17 Dec 2013 11:24:38 +0800
Subject: ASoC: Add SAI SoC Digital Audio Interface driver.
This adds Freescale SAI ASoC Audio support.
This implementation is only compatible with device tree definition.
Features:
o Supports playback/capture
o Supports 16/20/24 bit PCM
o Supports 8k - 96k sample rates
o Supports master and slave mode.
Signed-off-by: Alison Wang
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 492 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 492 insertions(+)
create mode 100644 sound/soc/fsl/fsl_sai.c
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
new file mode 100644
index 000000000000..50a797e65781
--- /dev/null
+++ b/sound/soc/fsl/fsl_sai.c
@@ -0,0 +1,492 @@
+/*
+ * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software, you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or(at your
+ * option) any later version.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "fsl_sai.h"
+
+static inline u32 sai_readl(struct fsl_sai *sai,
+ const void __iomem *addr)
+{
+ u32 val;
+
+ val = __raw_readl(addr);
+
+ if (likely(sai->big_endian_regs))
+ val = be32_to_cpu(val);
+ else
+ val = le32_to_cpu(val);
+ rmb();
+
+ return val;
+}
+
+static inline void sai_writel(struct fsl_sai *sai,
+ u32 val, void __iomem *addr)
+{
+ wmb();
+ if (likely(sai->big_endian_regs))
+ val = cpu_to_be32(val);
+ else
+ val = cpu_to_le32(val);
+
+ __raw_writel(val, addr);
+}
+
+static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int fsl_dir)
+{
+ u32 val_cr2, reg_cr2;
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (fsl_dir == FSL_FMT_TRANSMITTER)
+ reg_cr2 = FSL_SAI_TCR2;
+ else
+ reg_cr2 = FSL_SAI_RCR2;
+
+ val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ switch (clk_id) {
+ case FSL_SAI_CLK_BUS:
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+ val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
+ break;
+ case FSL_SAI_CLK_MAST1:
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
+ break;
+ case FSL_SAI_CLK_MAST2:
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
+ break;
+ case FSL_SAI_CLK_MAST3:
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ sai_writel(sai, val_cr2, sai->base + reg_cr2);
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ int ret;
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (dir == SND_SOC_CLOCK_IN)
+ return 0;
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
+ sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
+ sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
+
+ ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+ FSL_FMT_TRANSMITTER);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "Cannot set SAI's transmitter sysclk: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+ FSL_FMT_RECEIVER);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "Cannot set SAI's receiver sysclk: %d\n",
+ ret);
+ return ret;
+ }
+
+ clk_disable_unprepare(sai->clk);
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt, int fsl_dir)
+{
+ u32 val_cr2, val_cr3, val_cr4, reg_cr2, reg_cr3, reg_cr4;
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (fsl_dir == FSL_FMT_TRANSMITTER) {
+ reg_cr2 = FSL_SAI_TCR2;
+ reg_cr3 = FSL_SAI_TCR3;
+ reg_cr4 = FSL_SAI_TCR4;
+ } else {
+ reg_cr2 = FSL_SAI_RCR2;
+ reg_cr3 = FSL_SAI_RCR3;
+ reg_cr4 = FSL_SAI_RCR4;
+ }
+
+ val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ val_cr3 = sai_readl(sai, sai->base + reg_cr3);
+ val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+
+ if (sai->big_endian_data)
+ val_cr4 |= FSL_SAI_CR4_MF;
+ else
+ val_cr4 &= ~FSL_SAI_CR4_MF;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val_cr4 |= FSL_SAI_CR4_FSE;
+ val_cr4 |= FSL_SAI_CR4_FSP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val_cr4 |= FSL_SAI_CR4_FSP;
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val_cr4 |= FSL_SAI_CR4_FSP;
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val_cr3 |= FSL_SAI_CR3_TRCE;
+
+ if (fsl_dir == FSL_FMT_RECEIVER)
+ val_cr2 |= FSL_SAI_CR2_SYNC;
+
+ sai_writel(sai, val_cr2, sai->base + reg_cr2);
+ sai_writel(sai, val_cr3, sai->base + reg_cr3);
+ sai_writel(sai, val_cr4, sai->base + reg_cr4);
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ int ret;
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "Cannot set SAI's transmitter format: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "Cannot set SAI's receiver format: %d\n",
+ ret);
+ return ret;
+ }
+
+ clk_disable_unprepare(sai->clk);
+
+ return 0;
+}
+
+static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr, word_width;
+ unsigned int channels = params_channels(params);
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg_cr4 = FSL_SAI_TCR4;
+ reg_cr5 = FSL_SAI_TCR5;
+ reg_mr = FSL_SAI_TMR;
+ } else {
+ reg_cr4 = FSL_SAI_RCR4;
+ reg_cr5 = FSL_SAI_RCR5;
+ reg_mr = FSL_SAI_RMR;
+ }
+
+ val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
+ val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
+
+ val_cr5 = sai_readl(sai, sai->base + reg_cr5);
+ val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
+ val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
+ val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ word_width = 20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ word_width = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+ val_cr5 |= FSL_SAI_CR5_WNW(word_width);
+ val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+
+ if (sai->big_endian_data)
+ val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
+ else
+ val_cr5 |= FSL_SAI_CR5_FBT(0);
+
+ val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+ if (channels == 2 || channels == 1)
+ val_mr = ~0UL - ((1 << channels) - 1);
+ else
+ return -EINVAL;
+
+ sai_writel(sai, val_cr4, sai->base + reg_cr4);
+ sai_writel(sai, val_cr5, sai->base + reg_cr5);
+ sai_writel(sai, val_mr, sai->base + reg_mr);
+
+ return 0;
+}
+
+static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned int tcsr, rcsr;
+
+ tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
+ rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tcsr |= FSL_SAI_CSR_FRDE;
+ rcsr &= ~FSL_SAI_CSR_FRDE;
+ } else {
+ rcsr |= FSL_SAI_CSR_FRDE;
+ tcsr &= ~FSL_SAI_CSR_FRDE;
+ }
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ tcsr |= FSL_SAI_CSR_TERE;
+ rcsr |= FSL_SAI_CSR_TERE;
+ sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
+ tcsr &= ~FSL_SAI_CSR_TERE;
+ rcsr &= ~FSL_SAI_CSR_TERE;
+ }
+ sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fsl_sai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ int ret;
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ret = clk_prepare_enable(sai->clk);
+
+ return ret;
+}
+
+static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ clk_disable_unprepare(sai->clk);
+}
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt,
+ .hw_params = fsl_sai_hw_params,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+ .shutdown = fsl_sai_shutdown,
+};
+
+static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+
+ cpu_dai->playback_dma_data = &sai->dma_params_tx;
+ cpu_dai->capture_dma_data = &sai->dma_params_rx;
+
+ snd_soc_dai_set_drvdata(cpu_dai, sai);
+
+ return 0;
+}
+
+static int fsl_sai_dai_remove(struct snd_soc_dai *cpu_dai)
+{
+ cpu_dai->playback_dma_data = NULL;
+ cpu_dai->capture_dma_data = NULL;
+
+ snd_soc_dai_set_drvdata(cpu_dai, NULL);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_sai_dai = {
+ .probe = fsl_sai_dai_probe,
+ .remove = fsl_sai_dai_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .ops = &fsl_sai_pcm_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_component = {
+ .name = "fsl-sai",
+};
+
+static int fsl_sai_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct fsl_sai *sai;
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sai->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sai->base))
+ return PTR_ERR(sai->base);
+
+ sai->clk = devm_clk_get(&pdev->dev, "sai");
+ if (IS_ERR(sai->clk)) {
+ dev_err(&pdev->dev, "Cannot get SAI's clock\n");
+ return PTR_ERR(sai->clk);
+ }
+
+ 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;
+ sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+
+ sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+ sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
+ platform_set_drvdata(pdev, sai);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+ &fsl_sai_dai, 1);
+ if (ret)
+ return ret;
+
+ ret = snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int fsl_sai_remove(struct platform_device *pdev)
+{
+ snd_dmaengine_pcm_unregister(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id fsl_sai_ids[] = {
+ { .compatible = "fsl,vf610-sai", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver fsl_sai_driver = {
+ .probe = fsl_sai_probe,
+ .remove = fsl_sai_remove,
+
+ .driver = {
+ .name = "fsl-sai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_sai_ids,
+ },
+};
+module_platform_driver(fsl_sai_driver);
+
+MODULE_DESCRIPTION("Freescale Soc SAI Interface");
+MODULE_AUTHOR("Xiubo Li, ");
+MODULE_ALIAS("platform:fsl-sai");
+MODULE_LICENSE("GPL");
--
cgit v1.2.3
From a6af47ae5399baf4f5a2426b2121c1bcb9da4019 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Fri, 20 Dec 2013 12:17:38 +0800
Subject: ASoC: fsl-sai: Remove fsl_sai_remove()
There is no need of this function and makes the code slightly shorter
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 11 -----------
1 file changed, 11 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 50a797e65781..1868ec34be10 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -385,19 +385,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
-static int fsl_sai_dai_remove(struct snd_soc_dai *cpu_dai)
-{
- cpu_dai->playback_dma_data = NULL;
- cpu_dai->capture_dma_data = NULL;
-
- snd_soc_dai_set_drvdata(cpu_dai, NULL);
-
- return 0;
-}
-
static struct snd_soc_dai_driver fsl_sai_dai = {
.probe = fsl_sai_dai_probe,
- .remove = fsl_sai_dai_remove,
.playback = {
.channels_min = 1,
.channels_max = 2,
--
cgit v1.2.3
From e5180df3960b6130f17f3c5ab50d23674cdb2b5a Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Fri, 20 Dec 2013 12:30:26 +0800
Subject: ASoC: fsl-sai: Use devm_snd_dmaengine_pcm_register()
Makes the code slightly shorter
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 1868ec34be10..262d3107892e 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -443,19 +443,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int fsl_sai_remove(struct platform_device *pdev)
-{
- snd_dmaengine_pcm_unregister(&pdev->dev);
-
- return 0;
}
static const struct of_device_id fsl_sai_ids[] = {
@@ -465,8 +454,6 @@ static const struct of_device_id fsl_sai_ids[] = {
static struct platform_driver fsl_sai_driver = {
.probe = fsl_sai_probe,
- .remove = fsl_sai_remove,
-
.driver = {
.name = "fsl-sai",
.owner = THIS_MODULE,
--
cgit v1.2.3
From dd9f40602e96353c210805a99abd9af6abd28473 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Fri, 20 Dec 2013 12:35:33 +0800
Subject: ASoC: fsl-sai: Use snd_soc_dai_init_dma_data()
Makes the code slightly shorter
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 262d3107892e..b8cdbf8660fe 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -377,8 +377,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- cpu_dai->playback_dma_data = &sai->dma_params_tx;
- cpu_dai->capture_dma_data = &sai->dma_params_rx;
+ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+ &sai->dma_params_rx);
snd_soc_dai_set_drvdata(cpu_dai, sai);
--
cgit v1.2.3
From 1fb2d9d7465bcbb519c582fa4a3bd04ff4fce2d2 Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:00 +0800
Subject: ASoC: fsl_sai: Keep symmetry for clk_enable() and clk_disable()
There are two functions haven't clk_disable_unprepare() if having error.
Thus fix them.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index b8cdbf8660fe..69a375f48efe 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -111,7 +111,7 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
dev_err(cpu_dai->dev,
"Cannot set SAI's transmitter sysclk: %d\n",
ret);
- return ret;
+ goto err_clk;
}
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
@@ -120,12 +120,13 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
dev_err(cpu_dai->dev,
"Cannot set SAI's receiver sysclk: %d\n",
ret);
- return ret;
+ goto err_clk;
}
+err_clk:
clk_disable_unprepare(sai->clk);
- return 0;
+ return ret;
}
static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
@@ -222,7 +223,7 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
dev_err(cpu_dai->dev,
"Cannot set SAI's transmitter format: %d\n",
ret);
- return ret;
+ goto err_clk;
}
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
@@ -230,12 +231,13 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
dev_err(cpu_dai->dev,
"Cannot set SAI's receiver format: %d\n",
ret);
- return ret;
+ goto err_clk;
}
+err_clk:
clk_disable_unprepare(sai->clk);
- return 0;
+ return ret;
}
static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
--
cgit v1.2.3
From 1d7003092771bd2feec30e2f3e5a06aa33479e08 Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:01 +0800
Subject: ASoC: fsl_sai: Use snd_pcm_format_width()
Use common helper function snd_pcm_format_width() to make code neater.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 17 ++---------------
1 file changed, 2 insertions(+), 15 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 69a375f48efe..e68102e63521 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -244,9 +244,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr, word_width;
+ u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
unsigned int channels = params_channels(params);
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 word_width = snd_pcm_format_width(params_format(params));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg_cr4 = FSL_SAI_TCR4;
@@ -267,20 +268,6 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- word_width = 16;
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- word_width = 20;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- word_width = 24;
- break;
- default:
- return -EINVAL;
- }
-
val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
--
cgit v1.2.3
From d22e28cce80a93578787d273bf1fa26a2be2636b Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:02 +0800
Subject: ASoC: fsl_sai: Drop useless channels check in hw_params()
SAi only supports two data channels on hardware level and the driver also does
register the min->1 and max->2, so no need to check channels.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index e68102e63521..8450bff6fb13 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -278,10 +278,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 |= FSL_SAI_CR5_FBT(0);
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
- if (channels == 2 || channels == 1)
- val_mr = ~0UL - ((1 << channels) - 1);
- else
- return -EINVAL;
+ val_mr = ~0UL - ((1 << channels) - 1);
sai_writel(sai, val_cr4, sai->base + reg_cr4);
sai_writel(sai, val_cr5, sai->base + reg_cr5);
--
cgit v1.2.3
From 15b29dae6604d2d2daf586429ff12f26272a868a Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:03 +0800
Subject: ASoC: fsl_sai: Drop useless ret in startup()
We can save this ret to make the code neater.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 8450bff6fb13..fc4cd95ad0a9 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -334,12 +334,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- int ret;
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- ret = clk_prepare_enable(sai->clk);
-
- return ret;
+ return clk_prepare_enable(sai->clk);
}
static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
--
cgit v1.2.3
From 190af12dad975f2ea7d69d1c5c9d36fec64da767 Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:04 +0800
Subject: ASoC: fsl_sai: Make dev_err information neater
Since using dev_err() there's no need to mention SAI any more, it will
print the full name of the driver -- fsl_sai.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index fc4cd95ad0a9..68d666b491de 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -108,18 +108,14 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_TRANSMITTER);
if (ret) {
- dev_err(cpu_dai->dev,
- "Cannot set SAI's transmitter sysclk: %d\n",
- ret);
+ dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
goto err_clk;
}
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_RECEIVER);
if (ret) {
- dev_err(cpu_dai->dev,
- "Cannot set SAI's receiver sysclk: %d\n",
- ret);
+ dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
goto err_clk;
}
@@ -220,17 +216,13 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
if (ret) {
- dev_err(cpu_dai->dev,
- "Cannot set SAI's transmitter format: %d\n",
- ret);
+ dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
goto err_clk;
}
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
if (ret) {
- dev_err(cpu_dai->dev,
- "Cannot set SAI's receiver format: %d\n",
- ret);
+ dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
goto err_clk;
}
--
cgit v1.2.3
From 4e3a99f5b004b30bc604d82e5498700649148e0d Mon Sep 17 00:00:00 2001
From: Nicolin Chen
Date: Fri, 20 Dec 2013 16:41:05 +0800
Subject: ASoC: fsl_sai: Sort local variable in general way
Generally we would write code for local variable like:
static new_func()
{
struct xxx *yyy;
...
int ret;
}
But this driver only follows this pattern for some functions, not all.
Thus this patch sorts the local variable in the general way.
Signed-off-by: Nicolin Chen
Reviewed-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 68d666b491de..b72132fa70de 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -53,8 +53,8 @@ static inline void sai_writel(struct fsl_sai *sai,
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
- u32 val_cr2, reg_cr2;
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 val_cr2, reg_cr2;
if (fsl_dir == FSL_FMT_TRANSMITTER)
reg_cr2 = FSL_SAI_TCR2;
@@ -90,8 +90,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- int ret;
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
if (dir == SND_SOC_CLOCK_IN)
return 0;
@@ -128,8 +128,8 @@ err_clk:
static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
unsigned int fmt, int fsl_dir)
{
- u32 val_cr2, val_cr3, val_cr4, reg_cr2, reg_cr3, reg_cr4;
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 val_cr2, val_cr3, val_cr4, reg_cr2, reg_cr3, reg_cr4;
if (fsl_dir == FSL_FMT_TRANSMITTER) {
reg_cr2 = FSL_SAI_TCR2;
@@ -207,8 +207,8 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- int ret;
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
ret = clk_prepare_enable(sai->clk);
if (ret)
@@ -236,9 +236,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
unsigned int channels = params_channels(params);
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
u32 word_width = snd_pcm_format_width(params_format(params));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -383,10 +383,10 @@ static const struct snd_soc_component_driver fsl_component = {
static int fsl_sai_probe(struct platform_device *pdev)
{
- int ret;
+ struct device_node *np = pdev->dev.of_node;
struct fsl_sai *sai;
struct resource *res;
- struct device_node *np = pdev->dev.of_node;
+ int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
--
cgit v1.2.3
From e6dc12d7198eddba2e3e7a13feab5c7edde7ba1d Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Wed, 25 Dec 2013 11:20:14 +0800
Subject: ASoC: fsl_sai: Move the global registers setting to _dai_probe()
Because we cannot make sure which one of _dai_fmt() and _dai_sysclk()
will be firstly called. So move the RCSR/TCSR and TCR1/RCR1's
initialization to _dai_probe(), and this can make sure that before any
of {T,R}CR{1~5} register to be set the RCSR/TCSR's RE/TE bit has been
cleared for the hareware limitation.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index b72132fa70de..596aabbf9037 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -100,11 +100,6 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
if (ret)
return ret;
- sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
- sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
- sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
-
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_TRANSMITTER);
if (ret) {
@@ -351,6 +346,18 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+ int ret;
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
+ sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
+ sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
+
+ clk_disable_unprepare(sai->clk);
snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
&sai->dma_params_rx);
--
cgit v1.2.3
From e5d0fa9c3ec59a40e0285d96b65b7f62875acd42 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Wed, 25 Dec 2013 12:40:04 +0800
Subject: ASoC: fsl_sai: Add disable operation for the corresponding data
channel.
Enables/Disables the corresponding data channel for tx/rx operation.
A channel must be enabled before its FIFO is accessed, and then disable
it when tx/rx is stopped or idle.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 596aabbf9037..af802465456e 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -124,20 +124,17 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
unsigned int fmt, int fsl_dir)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 val_cr2, val_cr3, val_cr4, reg_cr2, reg_cr3, reg_cr4;
+ u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
if (fsl_dir == FSL_FMT_TRANSMITTER) {
reg_cr2 = FSL_SAI_TCR2;
- reg_cr3 = FSL_SAI_TCR3;
reg_cr4 = FSL_SAI_TCR4;
} else {
reg_cr2 = FSL_SAI_RCR2;
- reg_cr3 = FSL_SAI_RCR3;
reg_cr4 = FSL_SAI_RCR4;
}
val_cr2 = sai_readl(sai, sai->base + reg_cr2);
- val_cr3 = sai_readl(sai, sai->base + reg_cr3);
val_cr4 = sai_readl(sai, sai->base + reg_cr4);
if (sai->big_endian_data)
@@ -188,13 +185,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- val_cr3 |= FSL_SAI_CR3_TRCE;
-
if (fsl_dir == FSL_FMT_RECEIVER)
val_cr2 |= FSL_SAI_CR2_SYNC;
sai_writel(sai, val_cr2, sai->base + reg_cr2);
- sai_writel(sai, val_cr3, sai->base + reg_cr3);
sai_writel(sai, val_cr4, sai->base + reg_cr4);
return 0;
@@ -278,7 +272,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int tcsr, rcsr;
+ u32 tcsr, rcsr, val_cr3, reg_cr3;
tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
@@ -286,17 +280,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tcsr |= FSL_SAI_CSR_FRDE;
rcsr &= ~FSL_SAI_CSR_FRDE;
+ reg_cr3 = FSL_SAI_TCR3;
} else {
rcsr |= FSL_SAI_CSR_FRDE;
tcsr &= ~FSL_SAI_CSR_FRDE;
+ reg_cr3 = FSL_SAI_RCR3;
}
+ val_cr3 = sai_readl(sai, sai->base + reg_cr3);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
tcsr |= FSL_SAI_CSR_TERE;
rcsr |= FSL_SAI_CSR_TERE;
+ val_cr3 |= FSL_SAI_CR3_TRCE;
+
+ sai_writel(sai, val_cr3, sai->base + reg_cr3);
sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
break;
@@ -308,8 +309,12 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
tcsr &= ~FSL_SAI_CSR_TERE;
rcsr &= ~FSL_SAI_CSR_TERE;
}
+
+ val_cr3 &= ~FSL_SAI_CR3_TRCE;
+
sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, val_cr3, sai->base + reg_cr3);
break;
default:
return -EINVAL;
--
cgit v1.2.3
From 496a39d9ec238569fac6daceac8f5420c5edc2f1 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Tue, 31 Dec 2013 15:33:21 +0800
Subject: ASoC: fsl_sai: Fix one bug for hardware limitation.
This is maybe one bug or a limitation of the hardware that the {T,R}CR2's
Synchronous Mode bits must be set as late as possible, or the SAI device
maybe hanged up, and there has not any explaination about this limitation
in the SAI Data Sheet.
And the {T,R}CR2's Synchronous Mode bits must be set at the same time whether
for Tx or Rx stream.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index af802465456e..2ece14716c67 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -145,7 +145,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
val_cr4 |= FSL_SAI_CR4_FSE;
- val_cr4 |= FSL_SAI_CR4_FSP;
break;
default:
return -EINVAL;
@@ -185,9 +184,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- if (fsl_dir == FSL_FMT_RECEIVER)
- val_cr2 |= FSL_SAI_CR2_SYNC;
-
sai_writel(sai, val_cr2, sai->base + reg_cr2);
sai_writel(sai, val_cr4, sai->base + reg_cr4);
@@ -253,6 +249,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+ val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
if (sai->big_endian_data)
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
else
@@ -272,7 +269,15 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 tcsr, rcsr, val_cr3, reg_cr3;
+ u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
+
+ val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
+ val_cr2 &= ~FSL_SAI_CR2_SYNC;
+ sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+
+ val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
+ val_cr2 |= FSL_SAI_CR2_SYNC;
+ sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
--
cgit v1.2.3
From 72aa62bed3ea30635156fad95f123a0b665072bf Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Tue, 31 Dec 2013 15:33:22 +0800
Subject: ASoC: fsl_sai: fix the endianess for SAI fifo data.
Revert the SAI's endianess for fifo data to/from DMA engine.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 2ece14716c67..5d38a6749b9f 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -138,9 +138,9 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr4 = sai_readl(sai, sai->base + reg_cr4);
if (sai->big_endian_data)
- val_cr4 |= FSL_SAI_CR4_MF;
- else
val_cr4 &= ~FSL_SAI_CR4_MF;
+ else
+ val_cr4 |= FSL_SAI_CR4_MF;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -251,9 +251,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
if (sai->big_endian_data)
- val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
- else
val_cr5 |= FSL_SAI_CR5_FBT(0);
+ else
+ val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
val_mr = ~0UL - ((1 << channels) - 1);
--
cgit v1.2.3
From 633ff8f8a4393b4a13b94eddd2613198c32035e6 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Wed, 8 Jan 2014 16:13:05 +0800
Subject: ASoC: fsl-sai: Clean up the code
Makes the code slightly shorter.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/fsl/fsl_sai.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
(limited to 'sound/soc/fsl/fsl_sai.c')
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 5d38a6749b9f..cdd3fa830704 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -62,26 +62,25 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
reg_cr2 = FSL_SAI_RCR2;
val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+
switch (clk_id) {
case FSL_SAI_CLK_BUS:
- val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
break;
case FSL_SAI_CLK_MAST1:
- val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
break;
case FSL_SAI_CLK_MAST2:
- val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
break;
case FSL_SAI_CLK_MAST3:
- val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
break;
default:
return -EINVAL;
}
+
sai_writel(sai, val_cr2, sai->base + reg_cr2);
return 0;
--
cgit v1.2.3