summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/lpass-rx-macro.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/lpass-rx-macro.c')
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c192
1 files changed, 160 insertions, 32 deletions
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 6ffe88345de5..6884ae505e33 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -5,6 +5,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <sound/pcm.h>
@@ -14,6 +15,8 @@
#include <linux/of_clk.h>
#include <linux/clk-provider.h>
+#include "lpass-macro-common.h"
+
#define CDC_RX_TOP_TOP_CFG0 (0x0000)
#define CDC_RX_TOP_SWR_CTRL (0x0008)
#define CDC_RX_TOP_DEBUG (0x000C)
@@ -606,9 +609,13 @@ struct rx_macro {
int is_softclip_on;
int is_aux_hpf_on;
int softclip_clk_users;
-
+ struct lpass_macro *pds;
struct regmap *regmap;
- struct clk_bulk_data clks[RX_NUM_CLKS_MAX];
+ struct clk *mclk;
+ struct clk *npl;
+ struct clk *macro;
+ struct clk *dcodec;
+ struct clk *fsgen;
struct clk_hw hw;
};
#define to_rx_macro(_hw) container_of(_hw, struct rx_macro, hw)
@@ -2039,6 +2046,10 @@ static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
int i;
int hph_pwr_mode;
+ /* AUX does not have compander */
+ if (comp == INTERP_AUX)
+ return 0;
+
if (!rx->comp_enabled[comp])
return 0;
@@ -2268,7 +2279,7 @@ static int rx_macro_mux_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
- ucontrol->value.integer.value[0] =
+ ucontrol->value.enumerated.item[0] =
rx->rx_port_value[widget->shift];
return 0;
}
@@ -2280,7 +2291,7 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
- u32 rx_port_value = ucontrol->value.integer.value[0];
+ u32 rx_port_value = ucontrol->value.enumerated.item[0];
u32 aif_rst;
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
@@ -2392,7 +2403,7 @@ static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
- ucontrol->value.integer.value[0] = rx->hph_pwr_mode;
+ ucontrol->value.enumerated.item[0] = rx->hph_pwr_mode;
return 0;
}
@@ -2402,7 +2413,7 @@ static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
- rx->hph_pwr_mode = ucontrol->value.integer.value[0];
+ rx->hph_pwr_mode = ucontrol->value.enumerated.item[0];
return 0;
}
@@ -3422,6 +3433,13 @@ static int rx_macro_component_probe(struct snd_soc_component *component)
static int swclk_gate_enable(struct clk_hw *hw)
{
struct rx_macro *rx = to_rx_macro(hw);
+ int ret;
+
+ ret = clk_prepare_enable(rx->mclk);
+ if (ret) {
+ dev_err(rx->dev, "unable to prepare mclk\n");
+ return ret;
+ }
rx_macro_mclk_enable(rx, true);
if (rx->reset_swr)
@@ -3448,6 +3466,7 @@ static void swclk_gate_disable(struct clk_hw *hw)
CDC_RX_SWR_CLK_EN_MASK, 0);
rx_macro_mclk_enable(rx, false);
+ clk_disable_unprepare(rx->mclk);
}
static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -3475,17 +3494,16 @@ static const struct clk_ops swclk_gate_ops = {
};
-static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx)
+static int rx_macro_register_mclk_output(struct rx_macro *rx)
{
struct device *dev = rx->dev;
- struct device_node *np = dev->of_node;
const char *parent_clk_name = NULL;
const char *clk_name = "lpass-rx-mclk";
struct clk_hw *hw;
struct clk_init_data init;
int ret;
- parent_clk_name = __clk_get_name(rx->clks[2].clk);
+ parent_clk_name = __clk_get_name(rx->npl);
init.name = clk_name;
init.ops = &swclk_gate_ops;
@@ -3494,13 +3512,11 @@ static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx)
init.num_parents = 1;
rx->hw.init = &init;
hw = &rx->hw;
- ret = clk_hw_register(rx->dev, hw);
+ ret = devm_clk_hw_register(rx->dev, hw);
if (ret)
- return ERR_PTR(ret);
-
- of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+ return ret;
- return NULL;
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct snd_soc_component_driver rx_macro_component_drv = {
@@ -3525,23 +3541,37 @@ static int rx_macro_probe(struct platform_device *pdev)
if (!rx)
return -ENOMEM;
- rx->clks[0].id = "macro";
- rx->clks[1].id = "dcodec";
- rx->clks[2].id = "mclk";
- rx->clks[3].id = "npl";
- rx->clks[4].id = "fsgen";
+ rx->macro = devm_clk_get_optional(dev, "macro");
+ if (IS_ERR(rx->macro))
+ return PTR_ERR(rx->macro);
- ret = devm_clk_bulk_get_optional(dev, RX_NUM_CLKS_MAX, rx->clks);
- if (ret) {
- dev_err(dev, "Error getting RX Clocks (%d)\n", ret);
- return ret;
- }
+ rx->dcodec = devm_clk_get_optional(dev, "dcodec");
+ if (IS_ERR(rx->dcodec))
+ return PTR_ERR(rx->dcodec);
+
+ rx->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(rx->mclk))
+ return PTR_ERR(rx->mclk);
+
+ rx->npl = devm_clk_get(dev, "npl");
+ if (IS_ERR(rx->npl))
+ return PTR_ERR(rx->npl);
+
+ rx->fsgen = devm_clk_get(dev, "fsgen");
+ if (IS_ERR(rx->fsgen))
+ return PTR_ERR(rx->fsgen);
+
+ rx->pds = lpass_macro_pds_init(dev);
+ if (IS_ERR(rx->pds))
+ return PTR_ERR(rx->pds);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
+ if (IS_ERR(rx->regmap))
+ return PTR_ERR(rx->regmap);
dev_set_drvdata(dev, rx);
@@ -3549,21 +3579,59 @@ static int rx_macro_probe(struct platform_device *pdev)
rx->dev = dev;
/* set MCLK and NPL rates */
- clk_set_rate(rx->clks[2].clk, MCLK_FREQ);
- clk_set_rate(rx->clks[3].clk, 2 * MCLK_FREQ);
+ clk_set_rate(rx->mclk, MCLK_FREQ);
+ clk_set_rate(rx->npl, 2 * MCLK_FREQ);
- ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks);
+ ret = clk_prepare_enable(rx->macro);
if (ret)
- return ret;
+ goto err;
+
+ ret = clk_prepare_enable(rx->dcodec);
+ if (ret)
+ goto err_dcodec;
+
+ ret = clk_prepare_enable(rx->mclk);
+ if (ret)
+ goto err_mclk;
+
+ ret = clk_prepare_enable(rx->npl);
+ if (ret)
+ goto err_npl;
+
+ ret = clk_prepare_enable(rx->fsgen);
+ if (ret)
+ goto err_fsgen;
- rx_macro_register_mclk_output(rx);
+ ret = rx_macro_register_mclk_output(rx);
+ if (ret)
+ goto err_clkout;
ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv,
rx_macro_dai,
ARRAY_SIZE(rx_macro_dai));
if (ret)
- clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+ goto err_clkout;
+
+
+ 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(rx->fsgen);
+err_fsgen:
+ clk_disable_unprepare(rx->npl);
+err_npl:
+ clk_disable_unprepare(rx->mclk);
+err_mclk:
+ clk_disable_unprepare(rx->dcodec);
+err_dcodec:
+ clk_disable_unprepare(rx->macro);
+err:
return ret;
}
@@ -3571,8 +3639,14 @@ static int rx_macro_remove(struct platform_device *pdev)
{
struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
- of_clk_del_provider(pdev->dev.of_node);
- clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+ clk_disable_unprepare(rx->mclk);
+ clk_disable_unprepare(rx->npl);
+ clk_disable_unprepare(rx->fsgen);
+ clk_disable_unprepare(rx->macro);
+ clk_disable_unprepare(rx->dcodec);
+
+ lpass_macro_pds_exit(rx->pds);
+
return 0;
}
@@ -3583,11 +3657,65 @@ static const struct of_device_id rx_macro_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
+static int __maybe_unused rx_macro_runtime_suspend(struct device *dev)
+{
+ struct rx_macro *rx = dev_get_drvdata(dev);
+
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
+
+ clk_disable_unprepare(rx->mclk);
+ clk_disable_unprepare(rx->npl);
+ clk_disable_unprepare(rx->fsgen);
+
+ return 0;
+}
+
+static int __maybe_unused rx_macro_runtime_resume(struct device *dev)
+{
+ struct rx_macro *rx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(rx->mclk);
+ if (ret) {
+ dev_err(dev, "unable to prepare mclk\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(rx->npl);
+ if (ret) {
+ dev_err(dev, "unable to prepare mclkx2\n");
+ goto err_npl;
+ }
+
+ ret = clk_prepare_enable(rx->fsgen);
+ if (ret) {
+ dev_err(dev, "unable to prepare fsgen\n");
+ goto err_fsgen;
+ }
+ regcache_cache_only(rx->regmap, false);
+ regcache_sync(rx->regmap);
+ rx->reset_swr = true;
+
+ return 0;
+err_fsgen:
+ clk_disable_unprepare(rx->npl);
+err_npl:
+ clk_disable_unprepare(rx->mclk);
+
+ return ret;
+}
+
+static const struct dev_pm_ops rx_macro_pm_ops = {
+ SET_RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL)
+};
+
static struct platform_driver rx_macro_driver = {
.driver = {
.name = "rx_macro",
.of_match_table = rx_macro_dt_match,
.suppress_bind_attrs = true,
+ .pm = &rx_macro_pm_ops,
},
.probe = rx_macro_probe,
.remove = rx_macro_remove,