Merge tag 'asoc-v5.18' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6-microblaze.git] / sound / soc / codecs / lpass-rx-macro.c
index aec5127..6884ae5 100644 (file)
@@ -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;
 }
 
@@ -2688,8 +2699,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
        int reg, b2_reg;
 
        /* Address does not automatically update if reading */
-       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
-       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
+       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg,
                                ((band_idx * BAND_MAX + coeff_idx) *
@@ -2718,7 +2729,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
 static void set_iir_band_coeff(struct snd_soc_component *component,
                               int iir_idx, int band_idx, uint32_t value)
 {
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg, (value & 0xFF));
        snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
@@ -2739,7 +2750,7 @@ static int rx_macro_put_iir_band_audio_mixer(
        int iir_idx = ctl->iir_idx;
        int band_idx = ctl->band_idx;
        u32 coeff[BAND_MAX];
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
 
        memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
 
@@ -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,