diff options
author | Walker Chen <walker.chen@starfivetech.com> | 2023-02-03 09:38:22 +0300 |
---|---|---|
committer | Walker Chen <walker.chen@starfivetech.com> | 2023-02-03 09:38:22 +0300 |
commit | 0265e10f4aac0621bb6e07ec2408eb69e8f28b7c (patch) | |
tree | 92f3cec36a5644f2200fb952838b05d50a3e5dc5 /sound/soc | |
parent | 7f21d0a774a952097ba9a7d3c60f9f7dc202acd1 (diff) | |
download | linux-0265e10f4aac0621bb6e07ec2408eb69e8f28b7c.tar.xz |
CR_3151_TDM_Hibernation_walker.chen
Resolved the error of reording and playing simultaneously after performing
hibernation resume.
Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/starfive/starfive_tdm.c | 100 |
1 files changed, 48 insertions, 52 deletions
diff --git a/sound/soc/starfive/starfive_tdm.c b/sound/soc/starfive/starfive_tdm.c index a3506e7d838d..8a763acca1d7 100644 --- a/sound/soc/starfive/starfive_tdm.c +++ b/sound/soc/starfive/starfive_tdm.c @@ -33,19 +33,9 @@ static inline void sf_tdm_writel(struct sf_tdm_dev *dev, u16 reg, u32 val) static void sf_tdm_save_context(struct sf_tdm_dev *dev) { dev->saved_reg_value[0] = sf_tdm_readl(dev, TDM_PCMGBCR); - dev->saved_reg_value[1] = sf_tdm_readl(dev, TDM_PCMTXCR); - dev->saved_reg_value[2] = sf_tdm_readl(dev, TDM_PCMRXCR); dev->saved_reg_value[3] = sf_tdm_readl(dev, TDM_PCMDIV); } -static void sf_tdm_restore_context(struct sf_tdm_dev *dev) -{ - sf_tdm_writel(dev, TDM_PCMGBCR, dev->saved_reg_value[0]); - sf_tdm_writel(dev, TDM_PCMTXCR, dev->saved_reg_value[1]); - sf_tdm_writel(dev, TDM_PCMRXCR, dev->saved_reg_value[2]); - sf_tdm_writel(dev, TDM_PCMDIV, dev->saved_reg_value[3]); -} - static void sf_tdm_start(struct sf_tdm_dev *dev, struct snd_pcm_substream *substream) { u32 data; @@ -76,10 +66,6 @@ static void sf_tdm_stop(struct sf_tdm_dev *dev, struct snd_pcm_substream *substr val &= ~PCMRXCR_RXEN; sf_tdm_writel(dev, TDM_PCMRXCR, val); } - - val = sf_tdm_readl(dev, TDM_PCMGBCR); - val &= ~PCMGBCR_ENABLE; - sf_tdm_writel(dev, TDM_PCMGBCR, val); } static int sf_tdm_syncdiv(struct sf_tdm_dev *dev) @@ -95,7 +81,7 @@ static int sf_tdm_syncdiv(struct sf_tdm_dev *dev) return -1; } - if ((dev->syncm == TDM_SYNCM_LONG) && + if ((dev->syncm == TDM_SYNCM_LONG) && ((dev->rx.sscale <= 1) || (dev->tx.sscale <= 1))) { if ((syncdiv + 1) <= sl) { pr_info("set syncdiv failed! it must be (syncdiv+1) > max[tx.sl, rx.sl]\n"); @@ -107,7 +93,7 @@ static int sf_tdm_syncdiv(struct sf_tdm_dev *dev) return 0; } -static void sf_tdm_contrl(struct sf_tdm_dev *dev) +static void sf_tdm_control(struct sf_tdm_dev *dev) { u32 data; @@ -122,7 +108,7 @@ static void sf_tdm_config(struct sf_tdm_dev *dev, struct snd_pcm_substream *subs { u32 datarx, datatx; - sf_tdm_contrl(dev); + sf_tdm_control(dev); sf_tdm_syncdiv(dev); datarx = (dev->rx.ifl << IFL_BIT) | @@ -219,7 +205,7 @@ static int sf_tdm_runtime_resume(struct device *dev) ret = reset_control_deassert(priv->resets); if (ret) { - dev_err(dev, "Failed to deassert tdm resets\n"); + dev_err(dev, "%s: failed to deassert tdm resets\n", __func__); goto err_reset; } @@ -250,6 +236,13 @@ static int sf_tdm_suspend(struct snd_soc_component *component) static int sf_tdm_resume(struct snd_soc_component *component) { + + struct sf_tdm_dev *dev = snd_soc_component_get_drvdata(component); + + // restore context + sf_tdm_writel(dev, TDM_PCMGBCR, dev->saved_reg_value[0]); + sf_tdm_writel(dev, TDM_PCMDIV, dev->saved_reg_value[3]); + return pm_runtime_force_resume(component->dev); } @@ -258,9 +251,9 @@ static int sf_tdm_resume(struct snd_soc_component *component) #define sf_tdm_resume NULL #endif -/* +/* * To stop dma first, we must implement this function, because it is - * called before stopping the stream. + * called before stopping the stream. */ static int sf_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) @@ -398,19 +391,19 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream, ret = clk_set_rate(dev->clk_mclk_inner, mclk_rate); if (ret) { - dev_info(dev->dev, "Can't set clk_mclk: %d\n", ret); + dev_err(dev->dev, "Can't set clk_mclk: %d\n", ret); return ret; } ret = clk_set_rate(dev->clk_tdm_internal, dev->pcmclk); if (ret) { - dev_info(dev->dev, "Can't set clk_tdm_internal: %d\n", ret); + dev_err(dev->dev, "Can't set clk_tdm_internal: %d\n", ret); return ret; } ret = clk_set_parent(dev->clk_tdm, dev->clk_tdm_ext); if (ret) { - dev_info(dev->dev, "Can't set clock source for clk_tdm: %d\n", ret); + dev_err(dev->dev, "Can't set clock source for clk_tdm: %d\n", ret); return ret; } @@ -428,6 +421,10 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream, sf_tdm_config(dev, substream); sf_tdm_save_context(dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dev->saved_reg_value[1] = sf_tdm_readl(dev, TDM_PCMTXCR); + else + dev->saved_reg_value[2] = sf_tdm_readl(dev, TDM_PCMRXCR); return 0; } @@ -443,7 +440,11 @@ static int sf_tdm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: dev->active++; - sf_tdm_restore_context(dev); + /* restore context */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sf_tdm_writel(dev, TDM_PCMTXCR, dev->saved_reg_value[1]); + else + sf_tdm_writel(dev, TDM_PCMRXCR, dev->saved_reg_value[2]); sf_tdm_start(dev, substream); break; @@ -529,8 +530,8 @@ static struct snd_soc_dai_driver sf_tdm_dai = { static const struct snd_pcm_hardware jh71xx_pcm_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), .buffer_bytes_max = 192512, @@ -615,12 +616,6 @@ static int sf_tdm_clk_reset_init(struct platform_device *pdev, struct sf_tdm_dev goto exit; } - ret = reset_control_assert(dev->resets); - if (ret) { - dev_err(&pdev->dev, "Failed to assert tdm resets\n"); - goto exit; - } - ret = clk_prepare_enable(dev->clk_mclk_inner); if (ret) { dev_err(&pdev->dev, "failed to prepare enable clk_mclk_inner\n"); @@ -630,68 +625,68 @@ static int sf_tdm_clk_reset_init(struct platform_device *pdev, struct sf_tdm_dev ret = clk_prepare_enable(dev->clk_ahb0); if (ret) { dev_err(&pdev->dev, "Failed to prepare enable clk_ahb0\n"); - goto dis_mclk_inner; + goto err_dis_ahb0; } ret = clk_prepare_enable(dev->clk_tdm_ahb); if (ret) { dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_ahb\n"); - goto dis_ahb0; + goto err_dis_tdm_ahb; } ret = clk_prepare_enable(dev->clk_apb0); if (ret) { dev_err(&pdev->dev, "Failed to prepare enable clk_apb0\n"); - goto dis_tdm_ahb; + goto err_dis_apb0; } ret = clk_prepare_enable(dev->clk_tdm_apb); if (ret) { dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_apb\n"); - goto dis_apb0; + goto err_dis_tdm_apb; } ret = clk_prepare_enable(dev->clk_tdm_internal); if (ret) { dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_intl\n"); - goto dis_tdm_apb; + goto err_dis_tdm_internal; } ret = clk_prepare_enable(dev->clk_tdm_ext); if (ret) { dev_err(&pdev->dev, "failed to prepare enable clk_tdm_ext\n"); - goto dis_tdm_internal; + goto err_dis_tdm_ext; } ret = clk_prepare_enable(dev->clk_tdm); if (ret) { dev_err(&pdev->dev, "failed to prepare enable clk_tdm\n"); - goto dis_tdm_ext; + goto err_dis_clk_tdm; } ret = reset_control_deassert(dev->resets); if (ret) { - dev_err(&pdev->dev, "Failed to deassert tdm resets\n"); - goto dis_tdm_clk; + dev_err(&pdev->dev, "%s: failed to deassert tdm resets\n", __func__); + goto err_clk_disable; } - + return 0; -dis_tdm_clk: +err_clk_disable: clk_disable_unprepare(dev->clk_tdm); -dis_tdm_ext: +err_dis_clk_tdm: clk_disable_unprepare(dev->clk_tdm_ext); -dis_tdm_internal: +err_dis_tdm_ext: clk_disable_unprepare(dev->clk_tdm_internal); -dis_tdm_apb: +err_dis_tdm_internal: clk_disable_unprepare(dev->clk_tdm_apb); -dis_apb0: +err_dis_tdm_apb: clk_disable_unprepare(dev->clk_apb0); -dis_tdm_ahb: +err_dis_apb0: clk_disable_unprepare(dev->clk_tdm_ahb); -dis_ahb0: +err_dis_tdm_ahb: clk_disable_unprepare(dev->clk_ahb0); -dis_mclk_inner: +err_dis_ahb0: clk_disable_unprepare(dev->clk_mclk_inner); exit: return ret; @@ -722,8 +717,8 @@ static int sf_tdm_probe(struct platform_device *pdev) dev->frame_mode = SHORT_LATER; tdm_init_params(dev); - dev_set_drvdata(&pdev->dev, dev); + dev_set_drvdata(&pdev->dev, dev); ret = devm_snd_soc_register_component(&pdev->dev, &sf_tdm_component, &sf_tdm_dai, 1); if (ret != 0) { @@ -760,10 +755,11 @@ MODULE_DEVICE_TABLE(of, sf_tdm_of_match); static const struct dev_pm_ops sf_tdm_pm_ops = { SET_RUNTIME_PM_OPS(sf_tdm_runtime_suspend, - sf_tdm_runtime_resume, NULL) + sf_tdm_runtime_resume, NULL) }; static struct platform_driver sf_tdm_driver = { + .driver = { .name = "jh7110-tdm", .of_match_table = sf_tdm_of_match, |