diff options
Diffstat (limited to 'drivers/clk/clk-fixed-rate.c')
| -rw-r--r-- | drivers/clk/clk-fixed-rate.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 45501637705c..6b4f76b9c4da 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -49,12 +49,24 @@ const struct clk_ops clk_fixed_rate_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); +static void devm_clk_hw_register_fixed_rate_release(struct device *dev, void *res) +{ + struct clk_fixed_rate *fix = res; + + /* + * We can not use clk_hw_unregister_fixed_rate, since it will kfree() + * the hw, resulting in double free. Just unregister the hw and let + * devres code kfree() it. + */ + clk_hw_unregister(&fix->hw); +} + struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, unsigned long fixed_rate, unsigned long fixed_accuracy, - unsigned long clk_fixed_flags) + unsigned long clk_fixed_flags, bool devm) { struct clk_fixed_rate *fixed; struct clk_hw *hw; @@ -62,7 +74,11 @@ struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev, int ret = -EINVAL; /* allocate fixed-rate clock */ - fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); + if (devm) + fixed = devres_alloc(devm_clk_hw_register_fixed_rate_release, + sizeof(*fixed), GFP_KERNEL); + else + fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); if (!fixed) return ERR_PTR(-ENOMEM); @@ -87,12 +103,16 @@ struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev, hw = &fixed->hw; if (dev || !np) ret = clk_hw_register(dev, hw); - else if (np) + else ret = of_clk_hw_register(np, hw); if (ret) { - kfree(fixed); + if (devm) + devres_free(fixed); + else + kfree(fixed); hw = ERR_PTR(ret); - } + } else if (devm) + devres_add(dev, fixed); return hw; } @@ -176,14 +196,12 @@ void __init of_fixed_clk_setup(struct device_node *node) } CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); -static int of_fixed_clk_remove(struct platform_device *pdev) +static void of_fixed_clk_remove(struct platform_device *pdev) { struct clk_hw *hw = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); clk_hw_unregister_fixed_rate(hw); - - return 0; } static int of_fixed_clk_probe(struct platform_device *pdev) |
