diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index 80751c15c300..4e8a4b27d7c7 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -14,12 +14,14 @@ #include +#ifndef CONFIG_COMMON_CLK #ifdef CONFIG_HAVE_MACH_CLKDEV #include #else #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) #endif +#endif static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) { diff --git a/arch/blackfin/include/asm/clkdev.h b/arch/blackfin/include/asm/clkdev.h index 9053beda8c50..7ac2436856a5 100644 --- a/arch/blackfin/include/asm/clkdev.h +++ b/arch/blackfin/include/asm/clkdev.h @@ -8,7 +8,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) return kzalloc(size, GFP_KERNEL); } +#ifndef CONFIG_COMMON_CLK #define __clk_put(clk) #define __clk_get(clk) ({ 1; }) +#endif #endif diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h index 262475414e5f..1b3ad7b09dc1 100644 --- a/arch/mips/include/asm/clkdev.h +++ b/arch/mips/include/asm/clkdev.h @@ -14,8 +14,10 @@ #include +#ifndef CONFIG_COMMON_CLK #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) +#endif static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) { diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h index 6ba91868201c..c41901465fb0 100644 --- a/arch/sh/include/asm/clkdev.h +++ b/arch/sh/include/asm/clkdev.h @@ -25,7 +25,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) return kzalloc(size, GFP_KERNEL); } +#ifndef CONFIG_COMMON_CLK #define __clk_put(clk) #define __clk_get(clk) ({ 1; }) +#endif #endif /* __CLKDEV_H__ */ diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c687dc8d0b64..baa2f66a7d19 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1813,6 +1813,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) clk->flags = hw->init->flags; clk->parent_names = hw->init->parent_names; clk->num_parents = hw->init->num_parents; + if (dev && dev->driver) + clk->owner = dev->driver->owner; + else + clk->owner = NULL; ret = __clk_init(dev, clk); if (ret) @@ -1833,6 +1837,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) goto fail_name; } clk->ops = hw->init->ops; + if (dev && dev->driver) + clk->owner = dev->driver->owner; clk->hw = hw; clk->flags = hw->init->flags; clk->num_parents = hw->init->num_parents; @@ -1973,6 +1979,26 @@ void devm_clk_unregister(struct device *dev, struct clk *clk) } EXPORT_SYMBOL_GPL(devm_clk_unregister); +/* + * clkdev helpers + */ +int __clk_get(struct clk *clk) +{ + if (clk && !try_module_get(clk->owner)) + return 0; + + return 1; +} + +void __clk_put(struct clk *clk) +{ + if (WARN_ON_ONCE(IS_ERR(clk))) + return; + + if (clk) + module_put(clk->owner); +} + /*** clk rate change notifiers ***/ /** diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 8138c94409f3..8cb1865e7d9d 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -25,10 +25,13 @@ #ifdef CONFIG_COMMON_CLK +struct module; + struct clk { const char *name; const struct clk_ops *ops; struct clk_hw *hw; + struct module *owner; struct clk *parent; const char **parent_names; struct clk **parents; diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index a6a6f603103b..94bad77eeb4a 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -43,4 +43,9 @@ int clk_add_alias(const char *, const char *, char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *, ...); int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); +#ifdef CONFIG_COMMON_CLK +int __clk_get(struct clk *clk); +void __clk_put(struct clk *clk); +#endif + #endif