summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@nxp.com>2017-07-13 13:42:42 +0300
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit7511009a7642ec86aac192d97623a415abbd3678 (patch)
tree967cee14b6a546bf841bcd453142ef0956d2ccb5
parentfd96483abf2647f79661fd97cc3003737881dfe1 (diff)
MLK-15937-4: ASoC: fsl_spdif: Use DMA workaround for SPDIF
Similar with commit 2f756e7aa88407 ("MLK-15004-4: ASoC: fsl_esai: esai workaround for imx8qxp Rev1") this is needed because of a hardware issue where SPDIF DMA request signal is active low but the DMA input is active high. The workaround uses GPT to convert DMA request signal to EDMA. Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.txt3
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2-spdif.dts1
-rw-r--r--sound/soc/fsl/fsl_spdif.c55
3 files changed, 58 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index 49f791510bf4..ee0fcb7fe95d 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -7,7 +7,8 @@ a fibre cable.
Required properties:
- compatible : Compatible list, must contain "fsl,imx35-spdif",
- "fsl,vf610-spdif", "fsl,imx8qm-spdif".
+ "fsl,vf610-spdif", "fsl,imx8qm-spdif",
+ "fsl,imx8qxp-v1-spdif"
- reg : Offset and length of the register set for the device.
diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2-spdif.dts b/arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2-spdif.dts
index aefbbff1aa9e..a4f0ecf4e4c4 100644
--- a/arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2-spdif.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2-spdif.dts
@@ -48,6 +48,7 @@
};
&spdif0 {
+ compatible = "fsl,imx8qxp-v1-spdif";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spdif0>;
dmas = <&edma2 23 0 7>, <&edma2 21 0 6>;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 2d39362f8e47..051b34791fd8 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -29,6 +29,7 @@
#include "fsl_spdif.h"
#include "imx-pcm.h"
+#include "fsl_dma_workaround.h"
#define FSL_SPDIF_TXFIFO_WML 0x8
#define FSL_SPDIF_RXFIFO_WML 0x8
@@ -51,6 +52,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
struct fsl_spdif_soc_data {
bool imx;
bool constrain_period_size;
+ bool dma_workaround;
u32 tx_burst;
u32 rx_burst;
u32 interrupts;
@@ -120,6 +122,7 @@ struct fsl_spdif_priv {
struct clk *sysclk;
struct clk *spbaclk;
const struct fsl_spdif_soc_data *soc;
+ struct fsl_dma_workaround_info *dma_info;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
/* regcache for SRPC */
@@ -128,6 +131,7 @@ struct fsl_spdif_priv {
static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
.imx = false,
+ .dma_workaround = false,
.tx_burst = FSL_SPDIF_TXFIFO_WML,
.rx_burst = FSL_SPDIF_RXFIFO_WML,
.interrupts = 1,
@@ -137,6 +141,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.imx = true,
+ .dma_workaround = false,
.tx_burst = FSL_SPDIF_TXFIFO_WML,
.rx_burst = FSL_SPDIF_RXFIFO_WML,
.interrupts = 1,
@@ -144,8 +149,24 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.constrain_period_size = false,
};
+/*
+ * In imx8qxp rev 1, the DMA request signal is not reverted. For SPDIF
+ * DMA request is low valid, but EDMA assert is high valid, so we
+ * need to use GPT to transfer the DMA request signal
+ */
+static struct fsl_spdif_soc_data fsl_spdif_imx8qxp_v1 = {
+ .imx = true,
+ .dma_workaround = true,
+ .tx_burst = 2,
+ .rx_burst = 2,
+ .interrupts = 2,
+ .tx_formats = SNDRV_PCM_FMTBIT_S24_LE,
+ .constrain_period_size = true,
+};
+
static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
.imx = true,
+ .dma_workaround = false,
.tx_burst = 2,
.rx_burst = 2,
.interrupts = 2,
@@ -615,6 +636,9 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
u32 sample_rate = params_rate(params);
int ret = 0;
+ if (spdif_priv->soc->dma_workaround)
+ configure_gpt_dma(substream, spdif_priv->dma_info);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = spdif_set_sample_rate(substream, sample_rate);
if (ret) {
@@ -663,11 +687,24 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
return 0;
}
+static int fsl_spdif_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ if (spdif_priv->soc->dma_workaround)
+ clear_gpt_dma(substream, spdif_priv->dma_info);
+
+ return 0;
+}
+
static struct snd_soc_dai_ops fsl_spdif_dai_ops = {
.startup = fsl_spdif_startup,
.hw_params = fsl_spdif_hw_params,
.trigger = fsl_spdif_trigger,
.shutdown = fsl_spdif_shutdown,
+ .hw_free = fsl_spdif_hw_free,
};
@@ -1298,6 +1335,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
}
static const struct of_device_id fsl_spdif_dt_ids[] = {
+ { .compatible = "fsl,imx8qxp-v1-spdif", .data = &fsl_spdif_imx8qxp_v1, },
{ .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
{ .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
{ .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
@@ -1448,6 +1486,12 @@ static int fsl_spdif_probe(struct platform_device *pdev)
if (of_property_read_u32(np, "fsl,dma-buffer-size", &buffer_size))
buffer_size = IMX_SPDIF_DMABUF_SIZE;
+ if (spdif_priv->soc->dma_workaround)
+ spdif_priv->dma_info =
+ fsl_dma_workaround_alloc_info("tcd_pool_spdif",
+ &pdev->dev,
+ "nxp,imx8qm-acm",
+ FSL_DMA_WORKAROUND_SPDIF);
ret = imx_pcm_dma_init(pdev, buffer_size);
if (ret)
dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
@@ -1455,6 +1499,16 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+ struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(&pdev->dev);
+
+ if (spdif_priv->soc->dma_workaround)
+ fsl_dma_workaround_free_info(spdif_priv->dma_info, &pdev->dev);
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int fsl_spdif_suspend(struct device *dev)
{
@@ -1522,6 +1576,7 @@ static struct platform_driver fsl_spdif_driver = {
.pm = &fsl_spdif_pm,
},
.probe = fsl_spdif_probe,
+ .remove = fsl_spdif_remove,
};
module_platform_driver(fsl_spdif_driver);