diff options
Diffstat (limited to 'drivers/clk/clk-fixed-factor.c')
-rw-r--r-- | drivers/clk/clk-fixed-factor.c | 119 |
1 files changed, 101 insertions, 18 deletions
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 8b343e59dc61..f734e34735a9 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -64,10 +64,24 @@ const struct clk_ops clk_fixed_factor_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); +static void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *res) +{ + struct clk_fixed_factor *fix = res; + + /* + * We can not use clk_hw_unregister_fixed_factor, 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); +} + static struct clk_hw * __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, - const char *name, const char *parent_name, int index, - unsigned long flags, unsigned int mult, unsigned int div) + const char *name, const char *parent_name, + const struct clk_hw *parent_hw, int index, + unsigned long flags, unsigned int mult, unsigned int div, + bool devm) { struct clk_fixed_factor *fix; struct clk_init_data init = { }; @@ -75,7 +89,15 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, struct clk_hw *hw; int ret; - fix = kmalloc(sizeof(*fix), GFP_KERNEL); + /* You can't use devm without a dev */ + if (devm && !dev) + return ERR_PTR(-EINVAL); + + if (devm) + fix = devres_alloc(devm_clk_hw_register_fixed_factor_release, + sizeof(*fix), GFP_KERNEL); + else + fix = kmalloc(sizeof(*fix), GFP_KERNEL); if (!fix) return ERR_PTR(-ENOMEM); @@ -89,6 +111,8 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, init.flags = flags; if (parent_name) init.parent_names = &parent_name; + else if (parent_hw) + init.parent_hws = &parent_hw; else init.parent_data = &pdata; init.num_parents = 1; @@ -99,19 +123,77 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, else ret = of_clk_hw_register(np, hw); if (ret) { - kfree(fix); + if (devm) + devres_free(fix); + else + kfree(fix); hw = ERR_PTR(ret); - } + } else if (devm) + devres_add(dev, fix); return hw; } +/** + * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with + * parent from DT index + * @dev: device that is registering this clock + * @name: name of this clock + * @index: index of phandle in @dev 'clocks' property + * @flags: fixed factor flags + * @mult: multiplier + * @div: divider + * + * Return: Pointer to fixed factor clk_hw structure that was registered or + * an error pointer. + */ +struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev, + const char *name, unsigned int index, unsigned long flags, + unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, index, + flags, mult, div, true); +} +EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index); + +/** + * devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with + * pointer to parent clock + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_hw: pointer to parent clk + * @flags: fixed factor flags + * @mult: multiplier + * @div: divider + * + * Return: Pointer to fixed factor clk_hw structure that was registered or + * an error pointer. + */ +struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev, + const char *name, const struct clk_hw *parent_hw, + unsigned long flags, unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw, + -1, flags, mult, div, true); +} +EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw); + +struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev, + const char *name, const struct clk_hw *parent_hw, + unsigned long flags, unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, + parent_hw, -1, flags, mult, div, + false); +} +EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw); + struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div) { - return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1, - flags, mult, div); + return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1, + flags, mult, div, false); } EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); @@ -153,17 +235,20 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw) } EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor); -#ifdef CONFIG_OF -static const struct of_device_id set_rate_parent_matches[] = { - { .compatible = "allwinner,sun4i-a10-pll3-2x-clk" }, - { /* Sentinel */ }, -}; +struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1, + flags, mult, div, true); +} +EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor); +#ifdef CONFIG_OF static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) { struct clk_hw *hw; const char *clk_name = node->name; - unsigned long flags = 0; u32 div, mult; int ret; @@ -181,11 +266,8 @@ static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) of_property_read_string(node, "clock-output-names", &clk_name); - if (of_match_node(set_rate_parent_matches, node)) - flags |= CLK_SET_RATE_PARENT; - - hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0, - flags, mult, div); + hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, NULL, 0, + 0, mult, div, false); if (IS_ERR(hw)) { /* * Clear OF_POPULATED flag so that clock registration can be @@ -206,6 +288,7 @@ static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) /** * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock + * @node: device node for the clock */ void __init of_fixed_factor_clk_setup(struct device_node *node) { |