diff options
Diffstat (limited to 'drivers/clk/clk-fixed-rate.c')
-rw-r--r-- | drivers/clk/clk-fixed-rate.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index ac68a6b40f0e..7d775954e26d 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); @@ -90,9 +106,13 @@ struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev, 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; } |