From 258954bfe6093b56c8aa6be4e3f1a9a9e200fd0c Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Wed, 8 Feb 2023 16:09:06 +0800 Subject: [PATCH] sound: starfive: I2S: Fixed error after hibernation when building module When I2S resume but WM8960 has not resume and no clock, I2S should use inner clock instead of wm8960's clock first. Signed-off-by: Xingyu Wu --- arch/riscv/boot/dts/starfive/jh7110.dtsi | 12 ++- sound/soc/starfive/starfive_i2s.c | 149 ++++++++++++++++++++++++++++++- 2 files changed, 153 insertions(+), 8 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 27c2384..1668c51 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -1203,10 +1203,13 @@ <&clkgen JH7110_I2SRX_3CH_BCLK_MST>, <&clkgen JH7110_I2SRX_3CH_LRCK_MST>, <&clkgen JH7110_I2SRX0_3CH_BCLK>, - <&clkgen JH7110_I2SRX0_3CH_LRCK>; + <&clkgen JH7110_I2SRX0_3CH_LRCK>, + <&clkgen JH7110_MCLK>, + <&mclk_ext>; clock-names = "apb0", "i2srx_apb", "i2srx_bclk_mst", "i2srx_lrck_mst", - "i2srx_bclk", "i2srx_lrck"; + "i2srx_bclk", "i2srx_lrck", + "mclk", "mclk_ext"; resets = <&rstgen RSTN_U0_I2SRX_3CH_APB>, <&rstgen RSTN_U0_I2SRX_3CH_BCLK>; reset-names = "rst_apb_rx", "rst_bclk_rx"; @@ -1229,14 +1232,15 @@ <&clkgen JH7110_I2SRX0_3CH_BCLK>, <&clkgen JH7110_I2SRX0_3CH_LRCK>, <&clkgen JH7110_MCLK>, + <&mclk_ext>, <&i2srx_bclk_ext>, <&i2srx_lrck_ext>; clock-names = "apb0", "3ch-apb", "audioroot", "mclk-inner", "bclk_mst", "3ch-lrck", "rx-bclk", "rx-lrck", - "mclk", "bclk-ext", - "lrck-ext"; + "mclk", "mclk_ext", + "bclk-ext", "lrck-ext"; resets = <&rstgen RSTN_U0_I2SRX_3CH_APB>, <&rstgen RSTN_U0_I2SRX_3CH_BCLK>; dmas = <&dma 24 1>; diff --git a/sound/soc/starfive/starfive_i2s.c b/sound/soc/starfive/starfive_i2s.c index b0c198e..45c0943 100644 --- a/sound/soc/starfive/starfive_i2s.c +++ b/sound/soc/starfive/starfive_i2s.c @@ -451,6 +451,17 @@ static int dw_i2s_runtime_resume(struct device *dev) return ret; } + if (dw_dev->rst_i2s_apb) { + ret = reset_control_deassert(dw_dev->rst_i2s_apb); + if (ret) + return ret; + } + if (dw_dev->rst_i2s_bclk) { + ret = reset_control_deassert(dw_dev->rst_i2s_bclk); + if (ret) + return ret; + } + return 0; } @@ -466,17 +477,79 @@ static int dw_i2s_resume(struct snd_soc_component *component) int stream; int ret; + if (!dev->is_master) { + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(dev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_mst.\n", + __func__); + goto exit; + } + + ret = clk_set_parent(dev->clk_i2s_lrck, dev->clk_i2s_lrck_mst); + if (ret) { + dev_err(dev->dev, "%s: failed to set clk_i2s_lrck parent to lrck_mst.\n", + __func__); + goto exit; + } + } + ret = pm_runtime_force_resume(component->dev); if (ret) return ret; + if (dev->syscon_base) { + if (dev->is_master) { + /* config i2s data source: PDM */ + regmap_update_bits(dev->syscon_base, dev->syscon_offset_34, + AUDIO_SDIN_MUX_MASK, I2SRX_DATA_SRC_PDM); + + regmap_update_bits(dev->syscon_base, dev->syscon_offset_18, + I2SRX_3CH_ADC_MASK, I2SRX_3CH_ADC_EN); + } else { + /*i2srx_3ch_adc_enable*/ + regmap_update_bits(dev->syscon_base, dev->syscon_offset_18, + 0x1 << 1, 0x1 << 1); + + /*set i2sdin_sel*/ + regmap_update_bits(dev->syscon_base, dev->syscon_offset_34, + (0x1 << 10) | (0x1 << 14) | (0x1<<17), (0x0<<10) | (0x0<<14) | (0x0<<17)); + } + } + for_each_component_dais(component, dai) { for_each_pcm_streams(stream) if (snd_soc_dai_stream_active(dai, stream)) dw_i2s_config(dev, stream); } + i2s_write_reg(dev->i2s_base, CCR, dev->ccr); + + if (!dev->is_master) { + ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); + if (ret) { + dev_err(dev->dev, "failed to set mclk parent to mclk_ext\n"); + goto exit; + } + + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_bclk_ext); + if (ret) { + dev_err(dev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_ext.\n", + __func__); + goto exit; + } + + ret = clk_set_parent(dev->clk_i2s_lrck, dev->clk_lrck_ext); + if (ret) { + dev_err(dev->dev, "%s: failed to set clk_i2s_lrck parent to lrck_ext.\n", + __func__); + goto exit; + } + } + return 0; + +exit: + return ret; } #else @@ -500,6 +573,8 @@ static int dw_i2srx_mst_clk_init(struct platform_device *pdev, struct dw_i2s_dev { .id = "i2srx_lrck_mst" }, { .id = "i2srx_bclk" }, { .id = "i2srx_lrck" }, + { .id = "mclk" }, + { .id = "mclk_ext" }, }; ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks); @@ -513,6 +588,8 @@ static int dw_i2srx_mst_clk_init(struct platform_device *pdev, struct dw_i2s_dev dev->clk_i2s_lrck_mst = clks[2].clk; dev->clk_i2s_bclk = clks[3].clk; dev->clk_i2s_lrck = clks[4].clk; + dev->clk_mclk = clks[5].clk; + dev->clk_mclk_ext = clks[6].clk; dev->rst_i2s_apb = devm_reset_control_get_exclusive(&pdev->dev, "rst_apb_rx"); if (IS_ERR(dev->rst_i2s_apb)) { @@ -528,15 +605,30 @@ static int dw_i2srx_mst_clk_init(struct platform_device *pdev, struct dw_i2s_dev goto exit; } - reset_control_assert(dev->rst_i2s_apb); - reset_control_assert(dev->rst_i2s_bclk); - ret = clk_prepare_enable(dev->clk_i2s_apb); if (ret) { dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_apb\n"); goto exit; } + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(&pdev->dev, "failed to set parent clk_i2s_bclk\n"); + goto err_dis_bclk_mst; + } + + ret = clk_set_parent(dev->clk_i2s_lrck, dev->clk_i2s_lrck_mst); + if (ret) { + dev_err(&pdev->dev, "failed to set parent clk_i2s_lrck\n"); + goto err_dis_bclk_mst; + } + + ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); + if (ret) { + dev_err(&pdev->dev, "failed to set mclk parent to mclk_ext\n"); + goto err_dis_bclk_mst; + } + ret = clk_prepare_enable(dev->clk_i2s_bclk_mst); if (ret) { dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk_mst\n"); @@ -548,6 +640,7 @@ static int dw_i2srx_mst_clk_init(struct platform_device *pdev, struct dw_i2s_dev regmap_update_bits(dev->syscon_base, dev->syscon_offset_18, I2SRX_3CH_ADC_MASK, I2SRX_3CH_ADC_EN); + return 0; err_dis_bclk_mst: @@ -568,6 +661,8 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de { .id = "rx-lrck" }, { .id = "bclk-ext" }, { .id = "lrck-ext" }, + { .id = "mclk" }, + { .id = "mclk_ext" }, }; ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks); @@ -583,6 +678,22 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de dev->clk_i2s_lrck = clks[4].clk; dev->clk_bclk_ext = clks[5].clk; dev->clk_lrck_ext = clks[6].clk; + dev->clk_mclk = clks[7].clk; + dev->clk_mclk_ext = clks[8].clk; + + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(&pdev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_mst.\n", + __func__); + goto exit; + } + + ret = clk_set_parent(dev->clk_i2s_lrck, dev->clk_i2s_lrck_mst); + if (ret) { + dev_err(&pdev->dev, "%s: failed to set clk_i2s_lrck parent to lrck_mst.\n", + __func__); + goto exit; + } ret = clk_prepare_enable(dev->clk_i2s_apb); if (ret) { @@ -622,6 +733,13 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de regmap_update_bits(dev->syscon_base, dev->syscon_offset_34, (0x1 << 10) | (0x1 << 14) | (0x1<<17), (0x0<<10) | (0x0<<14) | (0x0<<17)); + + ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); + if (ret) { + dev_err(&pdev->dev, "failed to set mclk parent to mclk_ext\n"); + goto disable_parent; + } + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_bclk_ext); if (ret) { dev_err(&pdev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_ext.\n", @@ -644,6 +762,7 @@ disable_rst: disable_bclk: clk_disable_unprepare(dev->clk_i2s_apb); disable_apb_clk: +exit: return ret; } @@ -770,6 +889,20 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de dev->clk_bclk_ext = clks[7].clk; dev->clk_lrck_ext = clks[8].clk; + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(&pdev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_mst.\n", + __func__); + goto exit; + } + + ret = clk_set_parent(dev->clk_i2s_lrck, dev->clk_i2s_lrck_mst); + if (ret) { + dev_err(&pdev->dev, "%s: failed to set clk_i2s_lrck parent to lrck_mst.\n", + __func__); + goto exit; + } + ret = clk_prepare_enable(dev->clk_i2s_apb); if (ret) { dev_err(&pdev->dev, "%s: failed to enable clk_i2s_apb\n", __func__); @@ -793,13 +926,19 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de dev_err(&pdev->dev, "%s: failed to reset control assert rsts\n", __func__); goto disable_rst; } - + udelay(5); ret = reset_control_deassert(dev->rst_i2s_apb); if (ret) { dev_err(&pdev->dev, "%s: failed to reset control deassert rsts\n", __func__); goto disable_rst; } + ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); + if (ret) { + dev_err(&pdev->dev, "failed to set mclk parent to mclk_ext\n"); + goto exit; + } + ret = clk_set_parent(dev->clk_i2s_bclk, dev->clk_bclk_ext); if (ret) { dev_err(&pdev->dev, "%s: failed to set clk_i2s_bclk parent to bclk_ext.\n", @@ -1192,10 +1331,12 @@ err_init: static int dw_i2s_remove(struct platform_device *pdev) { +#ifndef CONFIG_PM struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); clk_disable_unprepare(dev->clk_i2s_bclk_mst); clk_disable_unprepare(dev->clk_i2s_apb); +#endif pm_runtime_disable(&pdev->dev); return 0; -- 2.7.4