]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
ASoC: da7219: Fix clock handling around codec level probe
authorAdam Thomson <Adam.Thomson.Opensource@diasemi.com>
Tue, 11 Aug 2020 16:57:25 +0000 (17:57 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 17 Aug 2020 17:48:45 +0000 (18:48 +0100)
Previously the driver would use devm_* related functions at
the codec level probe() to allocate clock resources for MCLK
and the DAI clocks exposed by the device. This caused issues
when registering clocks on a re-probe (no device level
remove/prove involved) as the devm_* resources were never
freed up so the clocks were still registered from the previous
codec level probe().

This commit updates the clock handling for MCLK usage and DAI
clock provision to fix this discrepancy and allow the codec level
probe/remove functionality to operate as intended.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Link: https://lore.kernel.org/r/b92c461baeed27a6cd92e59e36a55c2547218683.1597164865.git.Adam.Thomson.Opensource@diasemi.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/da7219.c
sound/soc/codecs/da7219.h

index 3bdfd8c00602fa1114586b76c9a04c59fc7f70df..301d8be2c5f75fea08f88f55ff6a647b9192d535 100644 (file)
@@ -2117,14 +2117,26 @@ static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = {
 static int da7219_register_dai_clks(struct snd_soc_component *component)
 {
        struct device *dev = component->dev;
+       struct device_node *np = dev->of_node;
        struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
        struct da7219_pdata *pdata = da7219->pdata;
        const char *parent_name;
+       struct clk_hw_onecell_data *clk_data;
        int i, ret;
 
+       /* For DT platforms allocate onecell data for clock registration */
+       if (np) {
+               clk_data = kzalloc(struct_size(clk_data, hws, DA7219_DAI_NUM_CLKS),
+                                  GFP_KERNEL);
+               if (!clk_data)
+                       return -ENOMEM;
+
+               clk_data->num = DA7219_DAI_NUM_CLKS;
+               da7219->clk_hw_data = clk_data;
+       }
+
        for (i = 0; i < DA7219_DAI_NUM_CLKS; ++i) {
                struct clk_init_data init = {};
-               struct clk *dai_clk;
                struct clk_lookup *dai_clk_lookup;
                struct clk_hw *dai_clk_hw = &da7219->dai_clks_hw[i];
 
@@ -2160,22 +2172,20 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
                init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE;
                dai_clk_hw->init = &init;
 
-               dai_clk = devm_clk_register(dev, dai_clk_hw);
-               if (IS_ERR(dai_clk)) {
-                       dev_warn(dev, "Failed to register %s: %ld\n",
-                                init.name, PTR_ERR(dai_clk));
-                       ret = PTR_ERR(dai_clk);
+               ret = clk_hw_register(dev, dai_clk_hw);
+               if (ret) {
+                       dev_warn(dev, "Failed to register %s: %d\n", init.name,
+                                ret);
                        goto err;
                }
-               da7219->dai_clks[i] = dai_clk;
+               da7219->dai_clks[i] = dai_clk_hw->clk;
 
-               /* If we're using DT, then register as provider accordingly */
-               if (dev->of_node) {
-                       devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
-                                                   dai_clk_hw);
+               /* For DT setup onecell data, otherwise create lookup */
+               if (np) {
+                       da7219->clk_hw_data->hws[i] = dai_clk_hw;
                } else {
-                       dai_clk_lookup = clkdev_create(dai_clk, init.name,
-                                                      "%s", dev_name(dev));
+                       dai_clk_lookup = clkdev_hw_create(dai_clk_hw, init.name,
+                                                         "%s", dev_name(dev));
                        if (!dai_clk_lookup) {
                                ret = -ENOMEM;
                                goto err;
@@ -2185,21 +2195,58 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
                }
        }
 
+       /* If we're using DT, then register as provider accordingly */
+       if (np) {
+               ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+                                            da7219->clk_hw_data);
+               if (ret) {
+                       dev_err(dev, "Failed to register clock provider\n");
+                       goto err;
+               }
+       }
+
        return 0;
 
 err:
        do {
                if (da7219->dai_clks_lookup[i])
                        clkdev_drop(da7219->dai_clks_lookup[i]);
+
+               clk_hw_unregister(&da7219->dai_clks_hw[i]);
        } while (i-- > 0);
 
+       if (np)
+               kfree(da7219->clk_hw_data);
+
        return ret;
 }
+
+static void da7219_free_dai_clks(struct snd_soc_component *component)
+{
+       struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+       struct device_node *np = component->dev->of_node;
+       int i;
+
+       if (np)
+               of_clk_del_provider(np);
+
+       for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) {
+               if (da7219->dai_clks_lookup[i])
+                       clkdev_drop(da7219->dai_clks_lookup[i]);
+
+               clk_hw_unregister(&da7219->dai_clks_hw[i]);
+       }
+
+       if (np)
+               kfree(da7219->clk_hw_data);
+}
 #else
 static inline int da7219_register_dai_clks(struct snd_soc_component *component)
 {
        return 0;
 }
+
+static void da7219_free_dai_clks(struct snd_soc_component *component) {}
 #endif /* CONFIG_COMMON_CLK */
 
 static void da7219_handle_pdata(struct snd_soc_component *component)
@@ -2464,7 +2511,7 @@ static int da7219_probe(struct snd_soc_component *component)
        da7219_handle_pdata(component);
 
        /* Check if MCLK provided */
-       da7219->mclk = devm_clk_get(component->dev, "mclk");
+       da7219->mclk = clk_get(component->dev, "mclk");
        if (IS_ERR(da7219->mclk)) {
                if (PTR_ERR(da7219->mclk) != -ENOENT) {
                        ret = PTR_ERR(da7219->mclk);
@@ -2477,7 +2524,7 @@ static int da7219_probe(struct snd_soc_component *component)
        /* Register CCF DAI clock control */
        ret = da7219_register_dai_clks(component);
        if (ret)
-               return ret;
+               goto err_put_clk;
 
        /* Default PC counter to free-running */
        snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK,
@@ -2514,10 +2561,16 @@ static int da7219_probe(struct snd_soc_component *component)
        /* Initialise AAD block */
        ret = da7219_aad_init(component);
        if (ret)
-               goto err_disable_reg;
+               goto err_free_dai_clks;
 
        return 0;
 
+err_free_dai_clks:
+       da7219_free_dai_clks(component);
+
+err_put_clk:
+       clk_put(da7219->mclk);
+
 err_disable_reg:
        regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
        regulator_bulk_free(DA7219_NUM_SUPPLIES, da7219->supplies);
@@ -2528,18 +2581,11 @@ err_disable_reg:
 static void da7219_remove(struct snd_soc_component *component)
 {
        struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
-#ifdef CONFIG_COMMON_CLK
-       int i;
-#endif
 
        da7219_aad_exit(component);
 
-#ifdef CONFIG_COMMON_CLK
-       for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) {
-               if (da7219->dai_clks_lookup[i])
-                       clkdev_drop(da7219->dai_clks_lookup[i]);
-       }
-#endif
+       da7219_free_dai_clks(component);
+       clk_put(da7219->mclk);
 
        /* Supplies */
        regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
index 88b67fedd01b21238b7d1689811cf8e3e5f56fd7..94af88f5258992ce5a9ed54f9e5db50f2aee996b 100644 (file)
@@ -817,6 +817,7 @@ struct da7219_priv {
 
 #ifdef CONFIG_COMMON_CLK
        struct clk_hw dai_clks_hw[DA7219_DAI_NUM_CLKS];
+       struct clk_hw_onecell_data *clk_hw_data;
 #endif
        struct clk_lookup *dai_clks_lookup[DA7219_DAI_NUM_CLKS];
        struct clk *dai_clks[DA7219_DAI_NUM_CLKS];