sound: starfive: I2S: Fixed error after hibernation when building module
authorXingyu Wu <xingyu.wu@starfivetech.com>
Wed, 8 Feb 2023 08:09:06 +0000 (16:09 +0800)
committerXingyu Wu <xingyu.wu@starfivetech.com>
Fri, 10 Feb 2023 03:06:05 +0000 (11:06 +0800)
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 <xingyu.wu@starfivetech.com>
arch/riscv/boot/dts/starfive/jh7110.dtsi
sound/soc/starfive/starfive_i2s.c

index 27c2384..1668c51 100644 (file)
                                 <&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";
                                 <&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>;
index b0c198e..45c0943 100644 (file)
@@ -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;