diff options
author | Michael Walle <michael@walle.cc> | 2020-11-08 19:51:09 +0100 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2020-12-07 16:53:39 -0800 |
commit | 26792699fe3681102aa85f4ae6d39e80a6a7e6b6 (patch) | |
tree | 985ce0b951bc3e142918858ab1803eba18f70078 | |
parent | 4cb15934ba05b49784d9d47778af308e7ea50b69 (diff) | |
download | lwn-26792699fe3681102aa85f4ae6d39e80a6a7e6b6.tar.gz lwn-26792699fe3681102aa85f4ae6d39e80a6a7e6b6.zip |
clk: divider: add devm_clk_hw_register_divider_table()
This will simplify drivers which would only unregister the clk in their
remove() op.
Signed-off-by: Michael Walle <michael@walle.cc>
Link: https://lore.kernel.org/r/20201108185113.31377-6-michael@walle.cc
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r-- | drivers/clk/clk-divider.c | 34 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 27 |
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 8de12cb0c43d..c499799693cc 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -8,6 +8,7 @@ */ #include <linux/clk-provider.h> +#include <linux/device.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/io.h> @@ -578,3 +579,36 @@ void clk_hw_unregister_divider(struct clk_hw *hw) kfree(div); } EXPORT_SYMBOL_GPL(clk_hw_unregister_divider); + +static void devm_clk_hw_release_divider(struct device *dev, void *res) +{ + clk_hw_unregister_divider(*(struct clk_hw **)res); +} + +struct clk_hw *__devm_clk_hw_register_divider(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, + void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, spinlock_t *lock) +{ + struct clk_hw **ptr, *hw; + + ptr = devres_alloc(devm_clk_hw_release_divider, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + hw = __clk_hw_register_divider(dev, np, name, parent_name, parent_hw, + parent_data, flags, reg, shift, width, + clk_divider_flags, table, lock); + + if (!IS_ERR(hw)) { + *ptr = hw; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return hw; +} +EXPORT_SYMBOL_GPL(__devm_clk_hw_register_divider); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 33db52ff83a0..5f896df01f83 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -639,6 +639,12 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev, const struct clk_parent_data *parent_data, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); +struct clk_hw *__devm_clk_hw_register_divider(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, + void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, spinlock_t *lock); struct clk *clk_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -779,6 +785,27 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, (parent_data), (flags), (reg), (shift), \ (width), (clk_divider_flags), (table), \ (lock)) +/** + * devm_clk_hw_register_divider_table - register a table based divider clock + * with the clock framework (devres variant) + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @table: array of divider/value pairs ending with a div set to 0 + * @lock: shared register lock for this clock + */ +#define devm_clk_hw_register_divider_table(dev, name, parent_name, flags, \ + reg, shift, width, \ + clk_divider_flags, table, lock) \ + __devm_clk_hw_register_divider((dev), NULL, (name), (parent_name), \ + NULL, NULL, (flags), (reg), (shift), \ + (width), (clk_divider_flags), (table), \ + (lock)) void clk_unregister_divider(struct clk *clk); void clk_hw_unregister_divider(struct clk_hw *hw); |