diff options
author | Shengjiu Wang <shengjiu.wang@freescale.com> | 2017-07-05 15:28:33 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | 5e9e8fda8e18bfd1575e58f2e377f8d15f95a7f8 (patch) | |
tree | 7e9d5d59e8d819d8350c4b9295d08118f113a20e /sound/soc/fsl/fsl_spdif.c | |
parent | b29c693ab9a4c8a574fc958ade4d75b82b0263ac (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.c | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b210deef3b6d..f99934ea9f89 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -48,6 +48,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 @@ -110,12 +119,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) { @@ -509,6 +546,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: @@ -1252,12 +1300,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; u32 buffer_size; @@ -1271,9 +1328,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); @@ -1300,6 +1365,20 @@ static int fsl_spdif_probe(struct platform_device *pdev) dev_err(&pdev->dev, "could not claim irq %u\n", irq); 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"); @@ -1347,8 +1426,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; @@ -1423,13 +1502,6 @@ static const struct dev_pm_ops fsl_spdif_pm = { NULL) }; -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", |