From 15bbc61393d0543c3259a35dcc18131a0fb20926 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 16 Sep 2014 19:18:49 +0800 Subject: MLK-11429-1: ASoC: fsl_spdif: don't change the root clock rate of spdif in driver cherry-pick below patch from imx_3.14.y ENGR00331799-2 ASoC: fsl_spdif: don't change the root clock rate of spdif in driver The spdif root clock may be used by other module or defined with CLK_SET_RATE_GATE, so we can't change the clock rate in driver. In this patch remove the clk_set_rate and clk_round_rate to protect the clock. Signed-off-by: Shengjiu Wang (cherry picked from commit c77170b2c9a9737f6fd61a5ea85a43b90e8ef02b) [ Aisheng: fix incorrectly removing u64 rate_actual ] Signed-off-by: Dong Aisheng --- sound/soc/fsl/fsl_spdif.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 7858a5499ac5..b8ddefa763a1 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -2,7 +2,7 @@ // // Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver // -// Copyright (C) 2013 Freescale Semiconductor, Inc. +// Copyright (C) 2013-2015 Freescale Semiconductor, Inc. // // Based on stmp3xxx_spdif_dai.c // Vladimir Barinov @@ -378,7 +378,6 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, u32 stc, mask, rate; u16 sysclk_df; u8 clk, txclk_df; - int ret; switch (sample_rate) { case 32000: @@ -420,19 +419,6 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, sysclk_df = spdif_priv->sysclk_df[rate]; - /* Don't mess up the clocks from other modules */ - if (clk != STC_TXCLK_SPDIF_ROOT) - goto clk_set_bypass; - - /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ - ret = clk_set_rate(spdif_priv->txclk[rate], - 64 * sample_rate * txclk_df); - if (ret) { - dev_err(&pdev->dev, "failed to set tx clock rate\n"); - return ret; - } - -clk_set_bypass: dev_dbg(&pdev->dev, "expected clock rate = %d\n", (64 * sample_rate * txclk_df * sysclk_df)); dev_dbg(&pdev->dev, "actual clock rate = %ld\n", @@ -1120,11 +1106,8 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { for (txclk_df = 1; txclk_df <= 128; txclk_df++) { - rate_ideal = rate[index] * txclk_df * 64ULL; - if (round) - rate_actual = clk_round_rate(clk, rate_ideal); - else - rate_actual = clk_get_rate(clk); + + rate_actual = clk_get_rate(clk); arate = rate_actual / 64; arate /= txclk_df * sysclk_df; -- cgit v1.2.3 From f675fa3778ff5496012693393a86918c8fdd682c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 19 May 2015 13:34:32 +0800 Subject: MLK-10903-1: ASoC: fsl_spdif: remove cache only in suspend/resume In imx6qp, there is no mega fast. After suspend, but before resume, there will be spdif interrupt, if set cache only in suspend, then we can't clear the interrupt, because regmap_write only write to cache. So the system will hang for the interrupt can't be cleared. Signed-off-by: Shengjiu Wang (cherry picked from commit 2a6a522c86d6c0fe80023c4327ca7ce4792035c8) --- sound/soc/fsl/fsl_spdif.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b8ddefa763a1..9dca6a1e430f 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1317,7 +1317,6 @@ static int fsl_spdif_suspend(struct device *dev) regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, &spdif_priv->regcache_srpc); - regcache_cache_only(spdif_priv->regmap, true); regcache_mark_dirty(spdif_priv->regmap); return 0; @@ -1327,8 +1326,6 @@ static int fsl_spdif_resume(struct device *dev) { struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); - regcache_cache_only(spdif_priv->regmap, false); - regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, spdif_priv->regcache_srpc); -- cgit v1.2.3 From 610e75569e835daa1cfae3f86a0027bb98c98436 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 26 Apr 2016 14:38:35 +0800 Subject: MLK-12722: ASoC: fsl_spdif: clear the validity bit for TX Validity bit is set in default, which means the data is not reliable, The receive device may drop this data. So clear it in default, and provide a mixer interface for user to control this bit. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 66 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 9dca6a1e430f..7a2a50cf06bc 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -2,7 +2,7 @@ // // Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver // -// Copyright (C) 2013-2015 Freescale Semiconductor, Inc. +// Copyright (C) 2013-2016 Freescale Semiconductor, Inc. // // Based on stmp3xxx_spdif_dai.c // Vladimir Barinov @@ -755,7 +755,7 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, } /* Valid bit information */ -static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, +static int fsl_spdif_rx_vbit_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; @@ -767,7 +767,7 @@ static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, } /* Get valid good bit from interrupt status register */ -static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, +static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); @@ -782,6 +782,46 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, return 0; } +static int fsl_spdif_tx_vbit_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val; + + regmap_read(regmap, REG_SPDIF_SCR, &val); + val = (val & SCR_VAL_MASK) >> SCR_VAL_OFFSET; + val = 1 - val; + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val = (1 - ucontrol->value.integer.value[0]) << SCR_VAL_OFFSET; + + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_VAL_MASK, val); + + return 0; +} + /* DPLL lock information */ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -939,11 +979,21 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { /* Valid bit error controller */ { .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "IEC958 V-Bit Errors", + .name = "IEC958 Rx V-Bit Errors", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_vbit_info, - .get = fsl_spdif_vbit_get, + .info = fsl_spdif_rx_vbit_info, + .get = fsl_spdif_rx_vbit_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Tx V-Bit", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_WRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = fsl_spdif_tx_vbit_info, + .get = fsl_spdif_tx_vbit_get, + .put = fsl_spdif_tx_vbit_put, }, /* DPLL lock info get controller */ { @@ -1292,6 +1342,10 @@ static int fsl_spdif_probe(struct platform_device *pdev) spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; + /*Clear the val bit for Tx*/ + regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SCR, + SCR_VAL_MASK, 1 << SCR_VAL_OFFSET); + /* Register with ASoC */ dev_set_drvdata(&pdev->dev, spdif_priv); -- cgit v1.2.3 From 38f89d3ce11e20437d326b4f6896d607174f5342 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 5 Jul 2017 15:28:33 +0800 Subject: 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 Reviewed-by: Daniel Baluta --- sound/soc/fsl/fsl_spdif.c | 91 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 9 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') 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", -- cgit v1.2.3 From c84933c819154957f09929ea8926854e459f7daa Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 12 Jul 2017 18:01:07 +0800 Subject: MLK-15960-3: ASoC: fsl_spdif: refine pm runtime function In imx8qm/imx8qxp, the power domain of IP is enabled when pm_runtime_get_sync() is called, and disabled when pm_runtime _put_sync() is called. when power domain is disabled, the value of registers will lost, so we need to use the regcache_sync() to restore the registers in fsl_spdif_runtime_resume. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 5d350689c2fb..c2dcf385dbdb 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -1443,6 +1444,32 @@ static int fsl_spdif_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_PM +static int fsl_spdif_runtime_resume(struct device *dev) +{ + struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); + + regcache_cache_only(spdif_priv->regmap, false); + regcache_mark_dirty(spdif_priv->regmap); + + regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, + SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, + spdif_priv->regcache_srpc); + + return regcache_sync(spdif_priv->regmap); +} + +static int fsl_spdif_runtime_suspend(struct device *dev) +{ + struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); + + regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, + &spdif_priv->regcache_srpc); + regcache_cache_only(spdif_priv->regmap, true); + return 0; +} +#endif + #ifdef CONFIG_PM_SLEEP static int fsl_spdif_suspend(struct device *dev) { @@ -1470,6 +1497,8 @@ static int fsl_spdif_resume(struct device *dev) static const struct dev_pm_ops fsl_spdif_pm = { SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume) + SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, + NULL) }; static struct platform_driver fsl_spdif_driver = { -- cgit v1.2.3 From c4f6be48fdc93d2e7a251e8e3edbfdf81fdfb8ea Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 29 Nov 2017 16:09:30 +0800 Subject: MLK-17034-6: ASoC: fsl_spdif: Move clock operation to pm runtime function In imx8 when systerm enter suspend state, the power of subsystem will be off, the clock enable state will be lost after resume, but the runtime resume function will be called after resume by pm, so need to move clock enablement to runtime resume and clock disablement to runtime suspend. Then after resume the clock enable state can be recovered. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 95 ++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 39 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index c2dcf385dbdb..8ffb0cccb7e1 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -486,25 +486,10 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, struct platform_device *pdev = spdif_priv->pdev; struct regmap *regmap = spdif_priv->regmap; u32 scr, mask; - int i; int ret; /* Reset module and interrupts only for first initialization */ if (!cpu_dai->active) { - ret = clk_prepare_enable(spdif_priv->coreclk); - if (ret) { - dev_err(&pdev->dev, "failed to enable core clock\n"); - return ret; - } - - if (!IS_ERR(spdif_priv->spbaclk)) { - ret = clk_prepare_enable(spdif_priv->spbaclk); - if (ret) { - dev_err(&pdev->dev, "failed to enable spba clock\n"); - goto err_spbaclk; - } - } - ret = spdif_softreset(spdif_priv); if (ret) { dev_err(&pdev->dev, "failed to soft reset\n"); @@ -522,18 +507,10 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) { - ret = clk_prepare_enable(spdif_priv->txclk[i]); - if (ret) - goto disable_txclk; - } } else { scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; - ret = clk_prepare_enable(spdif_priv->rxclk); - if (ret) - goto err; } regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); @@ -553,15 +530,7 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, return 0; -disable_txclk: - for (i--; i >= 0; i--) - clk_disable_unprepare(spdif_priv->txclk[i]); err: - if (!IS_ERR(spdif_priv->spbaclk)) - clk_disable_unprepare(spdif_priv->spbaclk); -err_spbaclk: - clk_disable_unprepare(spdif_priv->coreclk); - return ret; } @@ -571,20 +540,17 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); struct regmap *regmap = spdif_priv->regmap; - u32 scr, mask, i; + u32 scr, mask; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { scr = 0; mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) - clk_disable_unprepare(spdif_priv->txclk[i]); } else { scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; - clk_disable_unprepare(spdif_priv->rxclk); } regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); @@ -593,9 +559,6 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, spdif_intr_status_clear(spdif_priv); regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, SCR_LOW_POWER); - if (!IS_ERR(spdif_priv->spbaclk)) - clk_disable_unprepare(spdif_priv->spbaclk); - clk_disable_unprepare(spdif_priv->coreclk); } } @@ -1448,6 +1411,32 @@ static int fsl_spdif_probe(struct platform_device *pdev) static int fsl_spdif_runtime_resume(struct device *dev) { struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); + int ret; + int i; + + ret = clk_prepare_enable(spdif_priv->coreclk); + if (ret) { + dev_err(dev, "failed to enable core clock\n"); + return ret; + } + + if (!IS_ERR(spdif_priv->spbaclk)) { + ret = clk_prepare_enable(spdif_priv->spbaclk); + if (ret) { + dev_err(dev, "failed to enable spba clock\n"); + goto disable_core_clk; + } + } + + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { + ret = clk_prepare_enable(spdif_priv->txclk[i]); + if (ret) + goto disable_spba_clk; + } + + ret = clk_prepare_enable(spdif_priv->rxclk); + if (ret) + goto disable_tx_clk; regcache_cache_only(spdif_priv->regmap, false); regcache_mark_dirty(spdif_priv->regmap); @@ -1456,16 +1445,44 @@ static int fsl_spdif_runtime_resume(struct device *dev) SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, spdif_priv->regcache_srpc); - return regcache_sync(spdif_priv->regmap); + ret = regcache_sync(spdif_priv->regmap); + if (ret) + goto disable_rx_clk; + + return 0; + +disable_rx_clk: + clk_disable_unprepare(spdif_priv->rxclk); +disable_tx_clk: +disable_spba_clk: + for (i--; i >= 0; i--) + clk_disable_unprepare(spdif_priv->txclk[i]); + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); +disable_core_clk: + clk_disable_unprepare(spdif_priv->coreclk); + + return ret; } static int fsl_spdif_runtime_suspend(struct device *dev) { struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); + int i; regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, &spdif_priv->regcache_srpc); regcache_cache_only(spdif_priv->regmap, true); + + clk_disable_unprepare(spdif_priv->rxclk); + + for (i = 0; i < SPDIF_TXRATE_MAX; i++) + clk_disable_unprepare(spdif_priv->txclk[i]); + + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); + clk_disable_unprepare(spdif_priv->coreclk); + return 0; } #endif -- cgit v1.2.3 From 70e9a07d29d63c64fb365a5bb632621842f8e8d4 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 6 Dec 2017 10:42:30 +0800 Subject: MLK-17089-4: ASoC: fsl_spdif: support suspend & resume for imx8 Base on latest power management design in MLK-17074, every driver need to enter runtime suspend state in suspend, so the driver should call the pm_runtime_force_suspend in suspend. with this implementation the suspend function almost same as runtime suspend function. so remove the suspend function, just use pm_runtime_force_suspend instead. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8ffb0cccb7e1..bf3e8e6de1a2 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1487,33 +1487,8 @@ static int fsl_spdif_runtime_suspend(struct device *dev) } #endif -#ifdef CONFIG_PM_SLEEP -static int fsl_spdif_suspend(struct device *dev) -{ - struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); - - regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, - &spdif_priv->regcache_srpc); - - regcache_mark_dirty(spdif_priv->regmap); - - return 0; -} - -static int fsl_spdif_resume(struct device *dev) -{ - struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); - - regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, - SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, - spdif_priv->regcache_srpc); - - return regcache_sync(spdif_priv->regmap); -} -#endif /* CONFIG_PM_SLEEP */ - static const struct dev_pm_ops fsl_spdif_pm = { - SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, NULL) }; -- cgit v1.2.3 From 590ec64bb50a71c77b60b157d65b64846b56bb79 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 11 Jun 2018 15:54:03 +0800 Subject: MLK-18574: ASoC: fsl_spdif: support 192kHz for rx in imx8 The ipg clock is higher enough to support 192kHz in imx8 Signed-off-by: Shengjiu Wang Reviewed-by: Viorel Suman --- sound/soc/fsl/fsl_spdif.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index bf3e8e6de1a2..668b9bad02ff 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -50,6 +50,7 @@ struct fsl_spdif_soc_data { u32 rx_burst; u32 interrupts; u64 tx_formats; + u64 rx_rates; }; /* @@ -127,6 +128,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = { .rx_burst = FSL_SPDIF_RXFIFO_WML, .interrupts = 1, .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, + .rx_rates = FSL_SPDIF_RATES_CAPTURE, .constrain_period_size = false, }; @@ -136,6 +138,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = { .rx_burst = FSL_SPDIF_RXFIFO_WML, .interrupts = 1, .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, + .rx_rates = FSL_SPDIF_RATES_CAPTURE, .constrain_period_size = false, }; @@ -145,6 +148,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx8qm = { .rx_burst = 2, .interrupts = 2, .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, + .rx_rates = (FSL_SPDIF_RATES_CAPTURE | SNDRV_PCM_RATE_192000), .constrain_period_size = true, }; @@ -1295,6 +1299,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); spdif_priv->cpu_dai_drv.playback.formats = spdif_priv->soc->tx_formats; + spdif_priv->cpu_dai_drv.capture.rates = + spdif_priv->soc->rx_rates; /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From e3e48111d949a2ee17c24b5c91225afa28311ee7 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 12 Jun 2018 15:46:27 +0800 Subject: MLK-18574: ASoC: fsl_spdif: specify the spdif in imx8mm specify the spdif in imx8mm for the ipg clock is higher that it can support 192kHz Signed-off-by: Shengjiu Wang Reviewed-by: Viorel Suman --- sound/soc/fsl/fsl_spdif.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 668b9bad02ff..e31a134305c4 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -152,6 +152,16 @@ static struct fsl_spdif_soc_data fsl_spdif_imx8qm = { .constrain_period_size = true, }; +static struct fsl_spdif_soc_data fsl_spdif_imx8mm = { + .imx = true, + .tx_burst = FSL_SPDIF_TXFIFO_WML, + .rx_burst = FSL_SPDIF_RXFIFO_WML, + .interrupts = 1, + .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, + .rx_rates = (FSL_SPDIF_RATES_CAPTURE | SNDRV_PCM_RATE_192000), + .constrain_period_size = false, +}; + /* DPLL locked and lock loss interrupt handler */ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) { @@ -1262,6 +1272,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,imx8mm-spdif", .data = &fsl_spdif_imx8mm, }, { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, }, { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, }, { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, -- cgit v1.2.3 From 83fbe123247d174b41a985e4c4021939bf4e983e Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Wed, 8 Aug 2018 09:31:17 +0300 Subject: MLK-19115-1: ASoC: fsl_spdif: use snd_ctl_boolean_mono_info Remove redundant code and use snd_ctl_boolean_mono_info instead. Signed-off-by: Viorel Suman (cherry picked from commit 6ae5e1bf20eeff7e5ec821d96958329170359ce8) --- sound/soc/fsl/fsl_spdif.c | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index e31a134305c4..7d292e9f91ce 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -781,17 +781,6 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, } /* Valid bit information */ -static int fsl_spdif_rx_vbit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - - return 0; -} - /* Get valid good bit from interrupt status register */ static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -808,17 +797,6 @@ static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, return 0; } -static int fsl_spdif_tx_vbit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - - return 0; -} - static int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -915,18 +893,6 @@ static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, return 0; } -/* User bit sync mode info */ -static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - - return 0; -} - /* * User bit sync mode: * 1 CD User channel subcode @@ -1008,7 +974,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .name = "IEC958 Rx V-Bit Errors", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_rx_vbit_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_rx_vbit_get, }, { @@ -1017,7 +983,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_tx_vbit_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_tx_vbit_get, .put = fsl_spdif_tx_vbit_put, }, @@ -1037,7 +1003,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_usync_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_usync_get, .put = fsl_spdif_usync_put, }, -- cgit v1.2.3 From fff54ed842c9e88b6b3ece2a0f1616f92fbcfe79 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Wed, 8 Aug 2018 09:56:36 +0300 Subject: MLK-19115-2: ASoC: fsl_spdif: add support for enabling raw capture mode Since i.MX8 MQ SPDIF interface is able to capture raw data. Add support in SPDIF driver for this functionality. Signed-off-by: Viorel Suman (cherry picked from commit e13a302391f56a6bb547ff89e3fac73941cee429) --- sound/soc/fsl/fsl_spdif.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 7d292e9f91ce..92956d2e3865 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -826,6 +826,39 @@ static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, return 0; } +static int fsl_spdif_rx_rcm_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val; + + regmap_read(regmap, REG_SPDIF_SCR, &val); + val = (val & SCR_RAW_CAPTURE_MODE) ? 1 : 0; + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int fsl_spdif_rx_rcm_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val = (ucontrol->value.integer.value[0] ? SCR_RAW_CAPTURE_MODE : 0); + + if (val) + cpu_dai->driver->capture.formats |= SNDRV_PCM_FMTBIT_S32_LE; + else + cpu_dai->driver->capture.formats &= ~SNDRV_PCM_FMTBIT_S32_LE; + + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_RAW_CAPTURE_MODE, val); + + return 0; +} + /* DPLL lock information */ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1007,6 +1040,16 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .get = fsl_spdif_usync_get, .put = fsl_spdif_usync_put, }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Rx Raw Capture Mode Bit", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_WRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ctl_boolean_mono_info, + .get = fsl_spdif_rx_rcm_get, + .put = fsl_spdif_rx_rcm_put, + }, }; static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) -- cgit v1.2.3 From 1b4843721915e8bc76bdfd7148cd382c43b0f046 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Thu, 16 Aug 2018 14:17:35 +0300 Subject: MLK-19154-2: ASoC: fsl_spdif: keep all 7 TxClk sources Use txclk array to keep all 7 TxClk sources instead of keeping clocks per rate - need to do this in order to avoid multiple prepare_enable / disable_unprepare of the same clock during suspend/resume. Signed-off-by: Viorel Suman (cherry picked from commit 61bc5c83af0713a09b520486051a2efcbe852763) --- sound/soc/fsl/fsl_spdif.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 92956d2e3865..59214b148e28 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -110,7 +110,7 @@ struct fsl_spdif_priv { u16 sysclk_df[SPDIF_TXRATE_MAX]; u8 txclk_src[SPDIF_TXRATE_MAX]; u8 rxclk_src; - struct clk *txclk[SPDIF_TXRATE_MAX]; + struct clk *txclk[STC_TXCLK_SRC_MAX]; struct clk *rxclk; struct clk *coreclk; struct clk *sysclk; @@ -474,7 +474,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, dev_dbg(&pdev->dev, "expected clock rate = %d\n", (64 * sample_rate * txclk_df * sysclk_df)); dev_dbg(&pdev->dev, "actual clock rate = %ld\n", - clk_get_rate(spdif_priv->txclk[rate])); + clk_get_rate(spdif_priv->txclk[clk])); /* set fs field in consumer channel status */ spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); @@ -1240,12 +1240,10 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, struct device *dev = &pdev->dev; u64 savesub = 100000, ret; struct clk *clk; - char tmp[16]; int i; for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { - sprintf(tmp, "rxtx%d", i); - clk = devm_clk_get(&pdev->dev, tmp); + clk = spdif_priv->txclk[i]; if (IS_ERR(clk)) { dev_err(dev, "no rxtx%d clock in devicetree\n", i); return PTR_ERR(clk); @@ -1259,7 +1257,6 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, continue; savesub = ret; - spdif_priv->txclk[index] = clk; spdif_priv->txclk_src[index] = i; /* To quick catch a divisor, we allow a 0.1% deviation */ @@ -1271,7 +1268,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, spdif_priv->txclk_src[index], rate[index]); dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", spdif_priv->txclk_df[index], rate[index]); - if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk)) + if (clk_is_match(spdif_priv->txclk[spdif_priv->txclk_src[index]], spdif_priv->sysclk)) dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", spdif_priv->sysclk_df[index], rate[index]); dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", @@ -1298,6 +1295,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) const struct of_device_id *of_id; void __iomem *regs; int irq, ret, i; + char tmp[16]; if (!np) return -ENODEV; @@ -1361,8 +1359,17 @@ static int fsl_spdif_probe(struct platform_device *pdev) } } + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { + sprintf(tmp, "rxtx%d", i); + spdif_priv->txclk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(spdif_priv->txclk[i])) { + dev_err(&pdev->dev, "no rxtx%d clock in devicetree\n", i); + return PTR_ERR(spdif_priv->txclk[i]); + } + } + /* Get system clock for rx clock rate calculation */ - spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5"); + spdif_priv->sysclk = spdif_priv->txclk[5]; if (IS_ERR(spdif_priv->sysclk)) { dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n"); return PTR_ERR(spdif_priv->sysclk); @@ -1380,7 +1387,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "no spba clock in devicetree\n"); /* Select clock source for rx/tx clock */ - spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); + spdif_priv->rxclk = spdif_priv->txclk[1]; if (IS_ERR(spdif_priv->rxclk)) { dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); return PTR_ERR(spdif_priv->rxclk); @@ -1454,16 +1461,12 @@ static int fsl_spdif_runtime_resume(struct device *dev) } } - for (i = 0; i < SPDIF_TXRATE_MAX; i++) { + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { ret = clk_prepare_enable(spdif_priv->txclk[i]); if (ret) goto disable_spba_clk; } - ret = clk_prepare_enable(spdif_priv->rxclk); - if (ret) - goto disable_tx_clk; - regcache_cache_only(spdif_priv->regmap, false); regcache_mark_dirty(spdif_priv->regmap); @@ -1473,12 +1476,10 @@ static int fsl_spdif_runtime_resume(struct device *dev) ret = regcache_sync(spdif_priv->regmap); if (ret) - goto disable_rx_clk; + goto disable_tx_clk; return 0; -disable_rx_clk: - clk_disable_unprepare(spdif_priv->rxclk); disable_tx_clk: disable_spba_clk: for (i--; i >= 0; i--) @@ -1500,9 +1501,7 @@ static int fsl_spdif_runtime_suspend(struct device *dev) &spdif_priv->regcache_srpc); regcache_cache_only(spdif_priv->regmap, true); - clk_disable_unprepare(spdif_priv->rxclk); - - for (i = 0; i < SPDIF_TXRATE_MAX; i++) + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) clk_disable_unprepare(spdif_priv->txclk[i]); if (!IS_ERR(spdif_priv->spbaclk)) -- cgit v1.2.3 From 960f3f4848db6e2b0b83407e053dd0fed920e60a Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Thu, 16 Aug 2018 14:33:07 +0300 Subject: MLK-19154-3: ASoC: fsl_spdif: Add support for PLL switch at runtime. iMX8 platforms typically have 2 AUDIO PLLs being configured to handle 8k and 11k audio rates. The patch implements the functionality to select at runtime the appropriate AUDIO PLL as function of audio file rate. Signed-off-by: Viorel Suman (cherry picked from commit 3a29374cfbe0bfaf1785fa66163ffd3b9e30aca3) --- sound/soc/fsl/fsl_spdif.c | 303 ++++++++++++++++++++++++++++++---------------- 1 file changed, 199 insertions(+), 104 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 59214b148e28..eedf20e03a3f 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -120,6 +121,9 @@ struct fsl_spdif_priv { struct snd_dmaengine_dai_dma_data dma_params_rx; /* regcache for SRPC */ u32 regcache_srpc; + struct clk *pll8k_clk; + struct clk *pll11k_clk; + u8 streams; }; static struct fsl_spdif_soc_data fsl_spdif_vf610 = { @@ -602,6 +606,9 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); } + if (!ret) + spdif_priv->streams |= BIT(substream->stream); + return ret; } @@ -635,14 +642,197 @@ 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); + + spdif_priv->streams &= ~BIT(substream->stream); + + return 0; +} + +static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, + struct clk *clk, u64 savesub, + enum spdif_txrate index, bool round) +{ + static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; + bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); + u64 rate_actual, sub; + u32 arate; + u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; + u8 txclk_df; + + /* The sysclk has an extra divisor [2, 512] */ + sysclk_dfmin = is_sysclk ? 2 : 1; + sysclk_dfmax = is_sysclk ? 512 : 1; + + for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { + for (txclk_df = 1; txclk_df <= 128; txclk_df++) { + + rate_actual = clk_get_rate(clk); + + arate = rate_actual / 64; + arate /= txclk_df * sysclk_df; + + if (arate == rate[index]) { + /* We are lucky */ + savesub = 0; + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; + goto out; + } else if (arate / rate[index] == 1) { + /* A little bigger than expect */ + sub = (u64)(arate - rate[index]) * 100000; + do_div(sub, rate[index]); + if (sub >= savesub) + continue; + savesub = sub; + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; + } else if (rate[index] / arate == 1) { + /* A little smaller than expect */ + sub = (u64)(rate[index] - arate) * 100000; + do_div(sub, rate[index]); + if (sub >= savesub) + continue; + savesub = sub; + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; + } + } + } + +out: + return savesub; +} + +static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, + enum spdif_txrate index) +{ + static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; + struct platform_device *pdev = spdif_priv->pdev; + struct device *dev = &pdev->dev; + u64 savesub = 100000, ret; + struct clk *clk; + int i; + + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { + clk = spdif_priv->txclk[i]; + if (IS_ERR(clk)) { + dev_err(dev, "no rxtx%d clock in devicetree\n", i); + return PTR_ERR(clk); + } + if (!clk_get_rate(clk)) + continue; + + ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, + i == STC_TXCLK_SPDIF_ROOT); + if (savesub == ret) + continue; + + savesub = ret; + spdif_priv->txclk_src[index] = i; + + /* To quick catch a divisor, we allow a 0.1% deviation */ + if (savesub < 100) + break; + } + + dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", + spdif_priv->txclk_src[index], rate[index]); + dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", + spdif_priv->txclk_df[index], rate[index]); + if (clk_is_match(spdif_priv->txclk[spdif_priv->txclk_src[index]], spdif_priv->sysclk)) + dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", + spdif_priv->sysclk_df[index], rate[index]); + dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", + rate[index], spdif_priv->txrate[index]); + + return 0; +} + +static int fsl_spdif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct fsl_spdif_priv *data = snd_soc_dai_get_drvdata(cpu_dai); + struct platform_device *pdev = data->pdev; + struct device *dev = &pdev->dev; + struct clk *clk, *p, *pll = 0, *npll = 0; + u64 ratio = freq; + int ret, i; + + if (dir != SND_SOC_CLOCK_OUT || freq == 0 || clk_id != STC_TXCLK_SPDIF_ROOT) + return 0; + + if (data->pll8k_clk == NULL || data->pll11k_clk == NULL) + return 0; + + clk = data->txclk[clk_id]; + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "no rxtx%d clock in devicetree\n", clk_id); + return PTR_ERR(clk); + } + + p = clk; + while (p && data->pll8k_clk && data->pll11k_clk) { + struct clk *pp = clk_get_parent(p); + + if (clk_is_match(pp, data->pll8k_clk) || + clk_is_match(pp, data->pll11k_clk)) { + pll = pp; + break; + } + p = pp; + } + + if (pll) { + npll = (do_div(ratio, 8000) ? data->pll11k_clk : data->pll8k_clk); + if (!clk_is_match(pll, npll)) { + if (!data->streams) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(cpu_dai->dev, + "failed to set parent %s: %d\n", + __clk_get_name(npll), ret); + } else { + dev_err(cpu_dai->dev, + "PLL %s is in use by a running stream.\n", + __clk_get_name(pll)); + return -EINVAL; + } + } + } + + ret = clk_set_rate(clk, freq); + if (ret < 0) { + dev_err(cpu_dai->dev, "failed to set clock rate (%u): %d\n", + freq, ret); + return ret; + } + + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { + ret = fsl_spdif_probe_txclk(data, i); + if (ret) + return ret; + } + + return 0; +} + static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { .startup = fsl_spdif_startup, + .set_sysclk = fsl_spdif_set_dai_sysclk, .hw_params = fsl_spdif_hw_params, .trigger = fsl_spdif_trigger, .shutdown = fsl_spdif_shutdown, + .hw_free = fsl_spdif_hw_free, }; - /* * FSL SPDIF IEC958 controller(mixer) functions * @@ -1174,109 +1364,6 @@ static const struct regmap_config fsl_spdif_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, - struct clk *clk, u64 savesub, - enum spdif_txrate index, bool round) -{ - static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; - bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); - u64 rate_ideal, rate_actual, sub; - u32 arate; - u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; - u8 txclk_df; - - /* The sysclk has an extra divisor [2, 512] */ - sysclk_dfmin = is_sysclk ? 2 : 1; - sysclk_dfmax = is_sysclk ? 512 : 1; - - for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { - for (txclk_df = 1; txclk_df <= 128; txclk_df++) { - - rate_actual = clk_get_rate(clk); - - arate = rate_actual / 64; - arate /= txclk_df * sysclk_df; - - if (arate == rate[index]) { - /* We are lucky */ - savesub = 0; - spdif_priv->txclk_df[index] = txclk_df; - spdif_priv->sysclk_df[index] = sysclk_df; - spdif_priv->txrate[index] = arate; - goto out; - } else if (arate / rate[index] == 1) { - /* A little bigger than expect */ - sub = (u64)(arate - rate[index]) * 100000; - do_div(sub, rate[index]); - if (sub >= savesub) - continue; - savesub = sub; - spdif_priv->txclk_df[index] = txclk_df; - spdif_priv->sysclk_df[index] = sysclk_df; - spdif_priv->txrate[index] = arate; - } else if (rate[index] / arate == 1) { - /* A little smaller than expect */ - sub = (u64)(rate[index] - arate) * 100000; - do_div(sub, rate[index]); - if (sub >= savesub) - continue; - savesub = sub; - spdif_priv->txclk_df[index] = txclk_df; - spdif_priv->sysclk_df[index] = sysclk_df; - spdif_priv->txrate[index] = arate; - } - } - } - -out: - return savesub; -} - -static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, - enum spdif_txrate index) -{ - static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; - struct platform_device *pdev = spdif_priv->pdev; - struct device *dev = &pdev->dev; - u64 savesub = 100000, ret; - struct clk *clk; - int i; - - for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { - clk = spdif_priv->txclk[i]; - if (IS_ERR(clk)) { - dev_err(dev, "no rxtx%d clock in devicetree\n", i); - return PTR_ERR(clk); - } - if (!clk_get_rate(clk)) - continue; - - ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, - i == STC_TXCLK_SPDIF_ROOT); - if (savesub == ret) - continue; - - savesub = ret; - spdif_priv->txclk_src[index] = i; - - /* To quick catch a divisor, we allow a 0.1% deviation */ - if (savesub < 100) - break; - } - - dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", - spdif_priv->txclk_src[index], rate[index]); - dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", - spdif_priv->txclk_df[index], rate[index]); - if (clk_is_match(spdif_priv->txclk[spdif_priv->txclk_src[index]], spdif_priv->sysclk)) - dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", - spdif_priv->sysclk_df[index], rate[index]); - dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", - rate[index], spdif_priv->txrate[index]); - - return 0; -} - static const struct of_device_id fsl_spdif_dt_ids[] = { { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, }, { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, }, @@ -1394,6 +1481,14 @@ static int fsl_spdif_probe(struct platform_device *pdev) } spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; + spdif_priv->pll8k_clk = devm_clk_get(&pdev->dev, "pll8k"); + if (IS_ERR(spdif_priv->pll8k_clk)) + spdif_priv->pll8k_clk = NULL; + + spdif_priv->pll11k_clk = devm_clk_get(&pdev->dev, "pll11k"); + if (IS_ERR(spdif_priv->pll11k_clk)) + spdif_priv->pll11k_clk = NULL; + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { ret = fsl_spdif_probe_txclk(spdif_priv, i); if (ret) -- cgit v1.2.3 From 8e013fb268248049cc221513f6562b90882b4fc8 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Thu, 23 Aug 2018 13:18:25 +0300 Subject: MLK-19154-5: ASoC: fsl_spdif: refine PLL switch handling Allow PLL switch for playback stream only and remove PLL switch guard with regard to capture stream as the clock for capture stream is provided externally. Signed-off-by: Viorel Suman (cherry picked from commit c8213da5fbcd370acb4d764bef5df5981a517c11) --- sound/soc/fsl/fsl_spdif.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index eedf20e03a3f..a91d785461fd 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -123,7 +123,6 @@ struct fsl_spdif_priv { u32 regcache_srpc; struct clk *pll8k_clk; struct clk *pll11k_clk; - u8 streams; }; static struct fsl_spdif_soc_data fsl_spdif_vf610 = { @@ -606,9 +605,6 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); } - if (!ret) - spdif_priv->streams |= BIT(substream->stream); - return ret; } @@ -642,17 +638,6 @@ 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); - - spdif_priv->streams &= ~BIT(substream->stream); - - return 0; -} - static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, struct clk *clk, u64 savesub, enum spdif_txrate index, bool round) @@ -793,18 +778,11 @@ static int fsl_spdif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, if (pll) { npll = (do_div(ratio, 8000) ? data->pll11k_clk : data->pll8k_clk); if (!clk_is_match(pll, npll)) { - if (!data->streams) { - ret = clk_set_parent(p, npll); - if (ret < 0) - dev_warn(cpu_dai->dev, - "failed to set parent %s: %d\n", - __clk_get_name(npll), ret); - } else { - dev_err(cpu_dai->dev, - "PLL %s is in use by a running stream.\n", - __clk_get_name(pll)); - return -EINVAL; - } + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(cpu_dai->dev, + "failed to set parent %s: %d\n", + __clk_get_name(npll), ret); } } @@ -830,7 +808,6 @@ static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { .hw_params = fsl_spdif_hw_params, .trigger = fsl_spdif_trigger, .shutdown = fsl_spdif_shutdown, - .hw_free = fsl_spdif_hw_free, }; /* -- cgit v1.2.3 From ccea8f42a786297d39a70dff869764faeede7404 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Thu, 18 Apr 2019 15:25:44 +0300 Subject: MLK-21484-2: ASoC: fsl_spdif: ensure clk is unprepared before reparent On recent kernels clks which are marked with CLK_SET_RATE_GATE are "protected" against further changes at clk_prepare time, including clk reparent. Wrap clk set_parent and set_rate operations with disable_unprepare and prepare_enable. Signed-off-by: Viorel Suman --- sound/soc/fsl/fsl_spdif.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index a91d785461fd..4de132a064b6 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -750,6 +750,7 @@ static int fsl_spdif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, struct clk *clk, *p, *pll = 0, *npll = 0; u64 ratio = freq; int ret, i; + bool reparent = false; if (dir != SND_SOC_CLOCK_OUT || freq == 0 || clk_id != STC_TXCLK_SPDIF_ROOT) return 0; @@ -775,23 +776,22 @@ static int fsl_spdif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, p = pp; } - if (pll) { - npll = (do_div(ratio, 8000) ? data->pll11k_clk : data->pll8k_clk); - if (!clk_is_match(pll, npll)) { - ret = clk_set_parent(p, npll); - if (ret < 0) - dev_warn(cpu_dai->dev, - "failed to set parent %s: %d\n", - __clk_get_name(npll), ret); - } + npll = (do_div(ratio, 8000) ? data->pll11k_clk : data->pll8k_clk); + reparent = (pll && !clk_is_match(pll, npll)); + + clk_disable_unprepare(clk); + if (reparent) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(cpu_dai->dev, "failed to set parent %s: %d\n", + __clk_get_name(npll), ret); } ret = clk_set_rate(clk, freq); - if (ret < 0) { - dev_err(cpu_dai->dev, "failed to set clock rate (%u): %d\n", - freq, ret); - return ret; - } + if (ret < 0) + dev_warn(cpu_dai->dev, "failed to set clock rate (%u): %d\n", + freq, ret); + clk_prepare_enable(clk); for (i = 0; i < SPDIF_TXRATE_MAX; i++) { ret = fsl_spdif_probe_txclk(data, i); -- cgit v1.2.3 From 2d2076c4d0f8eb0f75cd07cbe3809ce150d5b085 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 2 Sep 2019 17:41:06 +0800 Subject: ASoC: fsl_spdif: Add pm_runtime_enable in probe Add pm_runtime_enable in probe Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 4de132a064b6..5d35805176ec 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1495,6 +1495,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SCR, SCR_VAL_MASK, 1 << SCR_VAL_OFFSET); + pm_runtime_enable(&pdev->dev); + /* Register with ASoC */ dev_set_drvdata(&pdev->dev, spdif_priv); -- cgit v1.2.3 From bd7b26036e8793d7fb915da6206706e3e6620ffa Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 20 Sep 2019 19:00:06 +0800 Subject: =?UTF-8?q?ASoC:=20fsl=5Fspdif=EF=BC=9ASupport=20multi=20power=20d?= =?UTF-8?q?omains?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support multi power domains Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 5d35805176ec..3ae6dd089ce4 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1360,6 +1361,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) void __iomem *regs; int irq, ret, i; char tmp[16]; + int num_domains = 0; if (!np) return -ENODEV; @@ -1423,6 +1425,24 @@ static int fsl_spdif_probe(struct platform_device *pdev) } } + num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + for (i = 0; i < num_domains; i++) { + struct device *pd_dev; + struct device_link *link; + + pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(pd_dev)) + return PTR_ERR(pd_dev); + + link = device_link_add(&pdev->dev, pd_dev, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(link)) + return PTR_ERR(link); + } + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { sprintf(tmp, "rxtx%d", i); spdif_priv->txclk[i] = devm_clk_get(&pdev->dev, tmp); -- cgit v1.2.3 From c7dad700c4263b990ded932d5524e4307100546c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 22 Nov 2019 15:46:20 +0800 Subject: LF-106: ASoC: fsl_spdif: request BUS_FREQ_HIGH request BUS_FREQ_HIGH Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_spdif.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/fsl/fsl_spdif.c') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3ae6dd089ce4..77901da5b8d8 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1561,6 +1562,8 @@ static int fsl_spdif_runtime_resume(struct device *dev) goto disable_spba_clk; } + request_bus_freq(BUS_FREQ_HIGH); + regcache_cache_only(spdif_priv->regmap, false); regcache_mark_dirty(spdif_priv->regmap); @@ -1595,6 +1598,8 @@ static int fsl_spdif_runtime_suspend(struct device *dev) &spdif_priv->regcache_srpc); regcache_cache_only(spdif_priv->regmap, true); + release_bus_freq(BUS_FREQ_HIGH); + for (i = 0; i < STC_TXCLK_SRC_MAX; i++) clk_disable_unprepare(spdif_priv->txclk[i]); -- cgit v1.2.3