aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/lpass-wsa-macro.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/lpass-wsa-macro.c')
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c178
1 files changed, 143 insertions, 35 deletions
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 75baf8eb7029..5e0abefe7cce 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -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"
@@ -337,7 +338,6 @@ struct wsa_macro {
int ec_hq[WSA_MACRO_RX1 + 1];
u16 prim_int_users[WSA_MACRO_RX1 + 1];
u16 wsa_mclk_users;
- bool reset_swr;
unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
int rx_port_value[WSA_MACRO_RX_MAX];
@@ -347,7 +347,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,30 +2260,31 @@ 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 */
- if (wsa->reset_swr)
- regmap_update_bits(regmap,
- CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
- CDC_WSA_SWR_RST_EN_MASK,
- CDC_WSA_SWR_RST_ENABLE);
+ regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE);
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK,
CDC_WSA_SWR_CLK_ENABLE);
/* Bring out of reset */
- if (wsa->reset_swr)
- regmap_update_bits(regmap,
- CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
- CDC_WSA_SWR_RST_EN_MASK,
- CDC_WSA_SWR_RST_DISABLE);
- wsa->reset_swr = false;
+ regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE);
} else {
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 +2355,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,49 +2393,92 @@ 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);
- wsa->reset_swr = true;
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,14 +2487,73 @@ 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"},
+ {.compatible = "qcom,sm8450-lpass-wsa-macro"},
+ {.compatible = "qcom,sc8280xp-lpass-wsa-macro" },
{}
};
MODULE_DEVICE_TABLE(of, wsa_macro_dt_match);
@@ -2455,6 +2562,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,