Merge tag 'driver-core-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / sound / soc / codecs / lpass-wsa-macro.c
index 75baf8e..27da6c6 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clk-provider.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <linux/pm_runtime.h>
 #include <linux/of_platform.h>
 #include <sound/tlv.h>
 #include "lpass-wsa-macro.h"
@@ -347,7 +348,11 @@ struct wsa_macro {
        int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
        int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
        struct regmap *regmap;
-       struct clk_bulk_data clks[WSA_NUM_CLKS_MAX];
+       struct clk *mclk;
+       struct clk *npl;
+       struct clk *macro;
+       struct clk *dcodec;
+       struct clk *fsgen;
        struct clk_hw hw;
 };
 #define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
@@ -2256,6 +2261,13 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
        struct regmap *regmap = wsa->regmap;
 
        if (enable) {
+               int ret;
+
+               ret = clk_prepare_enable(wsa->mclk);
+               if (ret) {
+                       dev_err(wsa->dev, "failed to enable mclk\n");
+                       return ret;
+               }
                wsa_macro_mclk_enable(wsa, true);
 
                /* reset swr ip */
@@ -2280,6 +2292,7 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
                regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
                                   CDC_WSA_SWR_CLK_EN_MASK, 0);
                wsa_macro_mclk_enable(wsa, false);
+               clk_disable_unprepare(wsa->mclk);
        }
 
        return 0;
@@ -2350,7 +2363,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
        struct clk_init_data init;
        int ret;
 
-       parent_clk_name = __clk_get_name(wsa->clks[2].clk);
+       parent_clk_name = __clk_get_name(wsa->npl);
 
        init.name = clk_name;
        init.ops = &swclk_gate_ops;
@@ -2388,23 +2401,33 @@ static int wsa_macro_probe(struct platform_device *pdev)
        if (!wsa)
                return -ENOMEM;
 
-       wsa->clks[0].id = "macro";
-       wsa->clks[1].id = "dcodec";
-       wsa->clks[2].id = "mclk";
-       wsa->clks[3].id = "npl";
-       wsa->clks[4].id = "fsgen";
+       wsa->macro = devm_clk_get_optional(dev, "macro");
+       if (IS_ERR(wsa->macro))
+               return PTR_ERR(wsa->macro);
 
-       ret = devm_clk_bulk_get(dev, WSA_NUM_CLKS_MAX, wsa->clks);
-       if (ret) {
-               dev_err(dev, "Error getting WSA Clocks (%d)\n", ret);
-               return ret;
-       }
+       wsa->dcodec = devm_clk_get_optional(dev, "dcodec");
+       if (IS_ERR(wsa->dcodec))
+               return PTR_ERR(wsa->dcodec);
+
+       wsa->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(wsa->mclk))
+               return PTR_ERR(wsa->mclk);
+
+       wsa->npl = devm_clk_get(dev, "npl");
+       if (IS_ERR(wsa->npl))
+               return PTR_ERR(wsa->npl);
+
+       wsa->fsgen = devm_clk_get(dev, "fsgen");
+       if (IS_ERR(wsa->fsgen))
+               return PTR_ERR(wsa->fsgen);
 
        base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
        wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+       if (IS_ERR(wsa->regmap))
+               return PTR_ERR(wsa->regmap);
 
        dev_set_drvdata(dev, wsa);
 
@@ -2412,25 +2435,59 @@ static int wsa_macro_probe(struct platform_device *pdev)
        wsa->dev = dev;
 
        /* set MCLK and NPL rates */
-       clk_set_rate(wsa->clks[2].clk, WSA_MACRO_MCLK_FREQ);
-       clk_set_rate(wsa->clks[3].clk, WSA_MACRO_MCLK_FREQ);
+       clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
+       clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
 
-       ret = clk_bulk_prepare_enable(WSA_NUM_CLKS_MAX, wsa->clks);
+       ret = clk_prepare_enable(wsa->macro);
        if (ret)
-               return ret;
+               goto err;
+
+       ret = clk_prepare_enable(wsa->dcodec);
+       if (ret)
+               goto err_dcodec;
+
+       ret = clk_prepare_enable(wsa->mclk);
+       if (ret)
+               goto err_mclk;
+
+       ret = clk_prepare_enable(wsa->npl);
+       if (ret)
+               goto err_npl;
+
+       ret = clk_prepare_enable(wsa->fsgen);
+       if (ret)
+               goto err_fsgen;
+
+       ret = wsa_macro_register_mclk_output(wsa);
+       if (ret)
+               goto err_clkout;
 
-       wsa_macro_register_mclk_output(wsa);
 
        ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv,
                                              wsa_macro_dai,
                                              ARRAY_SIZE(wsa_macro_dai));
        if (ret)
-               goto err;
+               goto err_clkout;
 
-       return ret;
-err:
-       clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
 
+       return 0;
+
+err_clkout:
+       clk_disable_unprepare(wsa->fsgen);
+err_fsgen:
+       clk_disable_unprepare(wsa->npl);
+err_npl:
+       clk_disable_unprepare(wsa->mclk);
+err_mclk:
+       clk_disable_unprepare(wsa->dcodec);
+err_dcodec:
+       clk_disable_unprepare(wsa->macro);
+err:
        return ret;
 
 }
@@ -2439,11 +2496,68 @@ static int wsa_macro_remove(struct platform_device *pdev)
 {
        struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
 
-       clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+       clk_disable_unprepare(wsa->macro);
+       clk_disable_unprepare(wsa->dcodec);
+       clk_disable_unprepare(wsa->mclk);
+       clk_disable_unprepare(wsa->npl);
+       clk_disable_unprepare(wsa->fsgen);
 
        return 0;
 }
 
+static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev)
+{
+       struct wsa_macro *wsa = dev_get_drvdata(dev);
+
+       regcache_cache_only(wsa->regmap, true);
+       regcache_mark_dirty(wsa->regmap);
+
+       clk_disable_unprepare(wsa->mclk);
+       clk_disable_unprepare(wsa->npl);
+       clk_disable_unprepare(wsa->fsgen);
+
+       return 0;
+}
+
+static int __maybe_unused wsa_macro_runtime_resume(struct device *dev)
+{
+       struct wsa_macro *wsa = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(wsa->mclk);
+       if (ret) {
+               dev_err(dev, "unable to prepare mclk\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(wsa->npl);
+       if (ret) {
+               dev_err(dev, "unable to prepare mclkx2\n");
+               goto err_npl;
+       }
+
+       ret = clk_prepare_enable(wsa->fsgen);
+       if (ret) {
+               dev_err(dev, "unable to prepare fsgen\n");
+               goto err_fsgen;
+       }
+
+       regcache_cache_only(wsa->regmap, false);
+       regcache_sync(wsa->regmap);
+
+       return 0;
+err_fsgen:
+       clk_disable_unprepare(wsa->npl);
+err_npl:
+       clk_disable_unprepare(wsa->mclk);
+
+       return ret;
+}
+
+static const struct dev_pm_ops wsa_macro_pm_ops = {
+       SET_RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL)
+};
+
 static const struct of_device_id wsa_macro_dt_match[] = {
        {.compatible = "qcom,sc7280-lpass-wsa-macro"},
        {.compatible = "qcom,sm8250-lpass-wsa-macro"},
@@ -2455,6 +2569,7 @@ static struct platform_driver wsa_macro_driver = {
        .driver = {
                .name = "wsa_macro",
                .of_match_table = wsa_macro_dt_match,
+               .pm = &wsa_macro_pm_ops,
        },
        .probe = wsa_macro_probe,
        .remove = wsa_macro_remove,