summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_spdif.c
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@freescale.com>2017-07-05 15:28:33 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:54:16 +0800
commit38f89d3ce11e20437d326b4f6896d607174f5342 (patch)
tree044052b55ceadbb047f230619f145c390ac7c000 /sound/soc/fsl/fsl_spdif.c
parent610e75569e835daa1cfae3f86a0027bb98c98436 (diff)
MLK-13947: ASoC: fsl_spdif: introduce SoC specific data
Introduce a SoC data struct which contains the differences between the different SoCs this driver supports. This makes it easy to support more differences without having to introduce a new switch/case each time. And in imx8qm, the spdif has two interrupt numbers and the burst size should be 2 for EDMA limitation to support dual FIFO. Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com> Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
Diffstat (limited to 'sound/soc/fsl/fsl_spdif.c')
-rw-r--r--sound/soc/fsl/fsl_spdif.c91
1 files changed, 82 insertions, 9 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 7a2a50cf06bc..5d350689c2fb 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -42,6 +42,15 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
#define DEFAULT_RXCLK_SRC 1
+struct fsl_spdif_soc_data {
+ bool imx;
+ bool constrain_period_size;
+ u32 tx_burst;
+ u32 rx_burst;
+ u32 interrupts;
+ u64 tx_formats;
+};
+
/*
* SPDIF control structure
* Defines channel status, subcode and Q sub
@@ -104,12 +113,40 @@ struct fsl_spdif_priv {
struct clk *coreclk;
struct clk *sysclk;
struct clk *spbaclk;
+ const struct fsl_spdif_soc_data *soc;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
/* regcache for SRPC */
u32 regcache_srpc;
};
+static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
+ .imx = false,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .interrupts = 1,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+ .constrain_period_size = false,
+};
+
+static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
+ .imx = true,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .interrupts = 1,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+ .constrain_period_size = false,
+};
+
+static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
+ .imx = true,
+ .tx_burst = 2,
+ .rx_burst = 2,
+ .interrupts = 2,
+ .tx_formats = SNDRV_PCM_FMTBIT_S24_LE,
+ .constrain_period_size = true,
+};
+
/* DPLL locked and lock loss interrupt handler */
static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
{
@@ -502,6 +539,17 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
/* Power up SPDIF module */
regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
+ if (spdif_priv->soc->constrain_period_size) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ spdif_priv->dma_params_tx.maxburst);
+ else
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ spdif_priv->dma_params_rx.maxburst);
+ }
+
return 0;
disable_txclk:
@@ -1245,12 +1293,21 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
return 0;
}
+static const struct of_device_id fsl_spdif_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
+ { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
+ { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
+
static int fsl_spdif_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct fsl_spdif_priv *spdif_priv;
struct spdif_mixer_control *ctrl;
struct resource *res;
+ const struct of_device_id *of_id;
void __iomem *regs;
int irq, ret, i;
@@ -1263,9 +1320,17 @@ static int fsl_spdif_probe(struct platform_device *pdev)
spdif_priv->pdev = pdev;
+ of_id = of_match_device(fsl_spdif_dt_ids, &pdev->dev);
+ if (!of_id || !of_id->data)
+ return -EINVAL;
+
+ spdif_priv->soc = of_id->data;
+
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
+ spdif_priv->cpu_dai_drv.playback.formats =
+ spdif_priv->soc->tx_formats;
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1291,6 +1356,21 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
+ if (spdif_priv->soc->interrupts > 1) {
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+ dev_name(&pdev->dev), spdif_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+ return ret;
+ }
+ }
+
/* Get system clock for rx clock rate calculation */
spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5");
if (IS_ERR(spdif_priv->sysclk)) {
@@ -1337,8 +1417,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
spdif_priv->dpll_locked = false;
- spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
- spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+ spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst;
+ spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst;
spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
@@ -1392,13 +1472,6 @@ static const struct dev_pm_ops fsl_spdif_pm = {
SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume)
};
-static const struct of_device_id fsl_spdif_dt_ids[] = {
- { .compatible = "fsl,imx35-spdif", },
- { .compatible = "fsl,vf610-spdif", },
- {}
-};
-MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
-
static struct platform_driver fsl_spdif_driver = {
.driver = {
.name = "fsl-spdif-dai",