diff options
Diffstat (limited to 'sound/soc/codecs/lpass-rx-macro.c')
-rw-r--r-- | sound/soc/codecs/lpass-rx-macro.c | 192 |
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, |