diff options
| -rw-r--r-- | drivers/clk/clk.c | 140 | ||||
| -rw-r--r-- | drivers/clk/clk.h | 10 | ||||
| -rw-r--r-- | drivers/clk/clkdev.c | 9 |
3 files changed, 98 insertions, 61 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d2477a5058ac..fef937ea44f4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
| @@ -3209,43 +3209,104 @@ unlock: | |||
| 3209 | return ret; | 3209 | return ret; |
| 3210 | } | 3210 | } |
| 3211 | 3211 | ||
| 3212 | struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, | 3212 | /** |
| 3213 | * clk_core_link_consumer - Add a clk consumer to the list of consumers in a clk_core | ||
| 3214 | * @core: clk to add consumer to | ||
| 3215 | * @clk: consumer to link to a clk | ||
| 3216 | */ | ||
| 3217 | static void clk_core_link_consumer(struct clk_core *core, struct clk *clk) | ||
| 3218 | { | ||
| 3219 | clk_prepare_lock(); | ||
| 3220 | hlist_add_head(&clk->clks_node, &core->clks); | ||
| 3221 | clk_prepare_unlock(); | ||
| 3222 | } | ||
| 3223 | |||
| 3224 | /** | ||
| 3225 | * clk_core_unlink_consumer - Remove a clk consumer from the list of consumers in a clk_core | ||
| 3226 | * @clk: consumer to unlink | ||
| 3227 | */ | ||
| 3228 | static void clk_core_unlink_consumer(struct clk *clk) | ||
| 3229 | { | ||
| 3230 | lockdep_assert_held(&prepare_lock); | ||
| 3231 | hlist_del(&clk->clks_node); | ||
| 3232 | } | ||
| 3233 | |||
| 3234 | /** | ||
| 3235 | * alloc_clk - Allocate a clk consumer, but leave it unlinked to the clk_core | ||
| 3236 | * @core: clk to allocate a consumer for | ||
| 3237 | * @dev_id: string describing device name | ||
| 3238 | * @con_id: connection ID string on device | ||
| 3239 | * | ||
| 3240 | * Returns: clk consumer left unlinked from the consumer list | ||
| 3241 | */ | ||
| 3242 | static struct clk *alloc_clk(struct clk_core *core, const char *dev_id, | ||
| 3213 | const char *con_id) | 3243 | const char *con_id) |
| 3214 | { | 3244 | { |
| 3215 | struct clk *clk; | 3245 | struct clk *clk; |
| 3216 | 3246 | ||
| 3217 | /* This is to allow this function to be chained to others */ | ||
| 3218 | if (IS_ERR_OR_NULL(hw)) | ||
| 3219 | return ERR_CAST(hw); | ||
| 3220 | |||
| 3221 | clk = kzalloc(sizeof(*clk), GFP_KERNEL); | 3247 | clk = kzalloc(sizeof(*clk), GFP_KERNEL); |
| 3222 | if (!clk) | 3248 | if (!clk) |
| 3223 | return ERR_PTR(-ENOMEM); | 3249 | return ERR_PTR(-ENOMEM); |
| 3224 | 3250 | ||
| 3225 | clk->core = hw->core; | 3251 | clk->core = core; |
| 3226 | clk->dev_id = dev_id; | 3252 | clk->dev_id = dev_id; |
| 3227 | clk->con_id = kstrdup_const(con_id, GFP_KERNEL); | 3253 | clk->con_id = kstrdup_const(con_id, GFP_KERNEL); |
| 3228 | clk->max_rate = ULONG_MAX; | 3254 | clk->max_rate = ULONG_MAX; |
| 3229 | 3255 | ||
| 3230 | clk_prepare_lock(); | ||
| 3231 | hlist_add_head(&clk->clks_node, &hw->core->clks); | ||
| 3232 | clk_prepare_unlock(); | ||
| 3233 | |||
| 3234 | return clk; | 3256 | return clk; |
| 3235 | } | 3257 | } |
| 3236 | 3258 | ||
| 3237 | /* keep in sync with __clk_put */ | 3259 | /** |
| 3238 | void __clk_free_clk(struct clk *clk) | 3260 | * free_clk - Free a clk consumer |
| 3261 | * @clk: clk consumer to free | ||
| 3262 | * | ||
| 3263 | * Note, this assumes the clk has been unlinked from the clk_core consumer | ||
| 3264 | * list. | ||
| 3265 | */ | ||
| 3266 | static void free_clk(struct clk *clk) | ||
| 3239 | { | 3267 | { |
| 3240 | clk_prepare_lock(); | ||
| 3241 | hlist_del(&clk->clks_node); | ||
| 3242 | clk_prepare_unlock(); | ||
| 3243 | |||
| 3244 | kfree_const(clk->con_id); | 3268 | kfree_const(clk->con_id); |
| 3245 | kfree(clk); | 3269 | kfree(clk); |
| 3246 | } | 3270 | } |
| 3247 | 3271 | ||
| 3248 | /** | 3272 | /** |
| 3273 | * clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given | ||
| 3274 | * a clk_hw | ||
| 3275 | * @hw: clk_hw associated with the clk being consumed | ||
| 3276 | * @dev_id: string describing device name | ||
| 3277 | * @con_id: connection ID string on device | ||
| 3278 | * | ||
| 3279 | * This is the main function used to create a clk pointer for use by clk | ||
| 3280 | * consumers. It connects a consumer to the clk_core and clk_hw structures | ||
| 3281 | * used by the framework and clk provider respectively. | ||
| 3282 | */ | ||
| 3283 | struct clk *clk_hw_create_clk(struct clk_hw *hw, | ||
| 3284 | const char *dev_id, const char *con_id) | ||
| 3285 | { | ||
| 3286 | struct clk *clk; | ||
| 3287 | struct clk_core *core; | ||
| 3288 | |||
| 3289 | /* This is to allow this function to be chained to others */ | ||
| 3290 | if (IS_ERR_OR_NULL(hw)) | ||
| 3291 | return ERR_CAST(hw); | ||
| 3292 | |||
| 3293 | core = hw->core; | ||
| 3294 | clk = alloc_clk(core, dev_id, con_id); | ||
| 3295 | if (IS_ERR(clk)) | ||
| 3296 | return clk; | ||
| 3297 | |||
| 3298 | if (!try_module_get(core->owner)) { | ||
| 3299 | free_clk(clk); | ||
| 3300 | return ERR_PTR(-ENOENT); | ||
| 3301 | } | ||
| 3302 | |||
| 3303 | kref_get(&core->ref); | ||
| 3304 | clk_core_link_consumer(core, clk); | ||
| 3305 | |||
| 3306 | return clk; | ||
| 3307 | } | ||
| 3308 | |||
| 3309 | /** | ||
| 3249 | * clk_register - allocate a new clock, register it and return an opaque cookie | 3310 | * clk_register - allocate a new clock, register it and return an opaque cookie |
| 3250 | * @dev: device that is registering this clock | 3311 | * @dev: device that is registering this clock |
| 3251 | * @hw: link to hardware-specific clock data | 3312 | * @hw: link to hardware-specific clock data |
| @@ -3320,17 +3381,27 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) | |||
| 3320 | 3381 | ||
| 3321 | INIT_HLIST_HEAD(&core->clks); | 3382 | INIT_HLIST_HEAD(&core->clks); |
| 3322 | 3383 | ||
| 3323 | hw->clk = __clk_create_clk(hw, NULL, NULL); | 3384 | /* |
| 3385 | * Don't call clk_hw_create_clk() here because that would pin the | ||
| 3386 | * provider module to itself and prevent it from ever being removed. | ||
| 3387 | */ | ||
| 3388 | hw->clk = alloc_clk(core, NULL, NULL); | ||
| 3324 | if (IS_ERR(hw->clk)) { | 3389 | if (IS_ERR(hw->clk)) { |
| 3325 | ret = PTR_ERR(hw->clk); | 3390 | ret = PTR_ERR(hw->clk); |
| 3326 | goto fail_parents; | 3391 | goto fail_parents; |
| 3327 | } | 3392 | } |
| 3328 | 3393 | ||
| 3394 | clk_core_link_consumer(hw->core, hw->clk); | ||
| 3395 | |||
| 3329 | ret = __clk_core_init(core); | 3396 | ret = __clk_core_init(core); |
| 3330 | if (!ret) | 3397 | if (!ret) |
| 3331 | return hw->clk; | 3398 | return hw->clk; |
| 3332 | 3399 | ||
| 3333 | __clk_free_clk(hw->clk); | 3400 | clk_prepare_lock(); |
| 3401 | clk_core_unlink_consumer(hw->clk); | ||
| 3402 | clk_prepare_unlock(); | ||
| 3403 | |||
| 3404 | free_clk(hw->clk); | ||
| 3334 | hw->clk = NULL; | 3405 | hw->clk = NULL; |
| 3335 | 3406 | ||
| 3336 | fail_parents: | 3407 | fail_parents: |
| @@ -3601,20 +3672,7 @@ EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); | |||
| 3601 | /* | 3672 | /* |
| 3602 | * clkdev helpers | 3673 | * clkdev helpers |
| 3603 | */ | 3674 | */ |
| 3604 | int __clk_get(struct clk *clk) | ||
| 3605 | { | ||
| 3606 | struct clk_core *core = !clk ? NULL : clk->core; | ||
| 3607 | |||
| 3608 | if (core) { | ||
| 3609 | if (!try_module_get(core->owner)) | ||
| 3610 | return 0; | ||
| 3611 | |||
| 3612 | kref_get(&core->ref); | ||
| 3613 | } | ||
| 3614 | return 1; | ||
| 3615 | } | ||
| 3616 | 3675 | ||
| 3617 | /* keep in sync with __clk_free_clk */ | ||
| 3618 | void __clk_put(struct clk *clk) | 3676 | void __clk_put(struct clk *clk) |
| 3619 | { | 3677 | { |
| 3620 | struct module *owner; | 3678 | struct module *owner; |
| @@ -3648,8 +3706,7 @@ void __clk_put(struct clk *clk) | |||
| 3648 | 3706 | ||
| 3649 | module_put(owner); | 3707 | module_put(owner); |
| 3650 | 3708 | ||
| 3651 | kfree_const(clk->con_id); | 3709 | free_clk(clk); |
| 3652 | kfree(clk); | ||
| 3653 | } | 3710 | } |
| 3654 | 3711 | ||
| 3655 | /*** clk rate change notifiers ***/ | 3712 | /*** clk rate change notifiers ***/ |
| @@ -4025,8 +4082,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, | |||
| 4025 | const char *dev_id, const char *con_id) | 4082 | const char *dev_id, const char *con_id) |
| 4026 | { | 4083 | { |
| 4027 | struct of_clk_provider *provider; | 4084 | struct of_clk_provider *provider; |
| 4028 | struct clk *clk = ERR_PTR(-EPROBE_DEFER); | 4085 | struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); |
| 4029 | struct clk_hw *hw; | ||
| 4030 | 4086 | ||
| 4031 | if (!clkspec) | 4087 | if (!clkspec) |
| 4032 | return ERR_PTR(-EINVAL); | 4088 | return ERR_PTR(-EINVAL); |
| @@ -4036,21 +4092,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, | |||
| 4036 | list_for_each_entry(provider, &of_clk_providers, link) { | 4092 | list_for_each_entry(provider, &of_clk_providers, link) { |
| 4037 | if (provider->node == clkspec->np) { | 4093 | if (provider->node == clkspec->np) { |
| 4038 | hw = __of_clk_get_hw_from_provider(provider, clkspec); | 4094 | hw = __of_clk_get_hw_from_provider(provider, clkspec); |
| 4039 | clk = __clk_create_clk(hw, dev_id, con_id); | 4095 | if (!IS_ERR(hw)) |
| 4040 | } | 4096 | break; |
| 4041 | |||
| 4042 | if (!IS_ERR(clk)) { | ||
| 4043 | if (!__clk_get(clk)) { | ||
| 4044 | __clk_free_clk(clk); | ||
| 4045 | clk = ERR_PTR(-ENOENT); | ||
| 4046 | } | ||
| 4047 | |||
| 4048 | break; | ||
| 4049 | } | 4097 | } |
| 4050 | } | 4098 | } |
| 4051 | mutex_unlock(&of_clk_mutex); | 4099 | mutex_unlock(&of_clk_mutex); |
| 4052 | 4100 | ||
| 4053 | return clk; | 4101 | return clk_hw_create_clk(hw, dev_id, con_id); |
| 4054 | } | 4102 | } |
| 4055 | 4103 | ||
| 4056 | /** | 4104 | /** |
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index b02f5e604e69..4cdf30b0008c 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h | |||
| @@ -12,24 +12,20 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, | |||
| 12 | #endif | 12 | #endif |
| 13 | 13 | ||
| 14 | #ifdef CONFIG_COMMON_CLK | 14 | #ifdef CONFIG_COMMON_CLK |
| 15 | struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, | 15 | struct clk *clk_hw_create_clk(struct clk_hw *hw, |
| 16 | const char *con_id); | 16 | const char *dev_id, const char *con_id); |
| 17 | void __clk_free_clk(struct clk *clk); | ||
| 18 | int __clk_get(struct clk *clk); | ||
| 19 | void __clk_put(struct clk *clk); | 17 | void __clk_put(struct clk *clk); |
| 20 | #else | 18 | #else |
| 21 | /* All these casts to avoid ifdefs in clkdev... */ | 19 | /* All these casts to avoid ifdefs in clkdev... */ |
| 22 | static inline struct clk * | 20 | static inline struct clk * |
| 23 | __clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) | 21 | clk_hw_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) |
| 24 | { | 22 | { |
| 25 | return (struct clk *)hw; | 23 | return (struct clk *)hw; |
| 26 | } | 24 | } |
| 27 | static inline void __clk_free_clk(struct clk *clk) { } | ||
| 28 | static struct clk_hw *__clk_get_hw(struct clk *clk) | 25 | static struct clk_hw *__clk_get_hw(struct clk *clk) |
| 29 | { | 26 | { |
| 30 | return (struct clk_hw *)clk; | 27 | return (struct clk_hw *)clk; |
| 31 | } | 28 | } |
| 32 | static inline int __clk_get(struct clk *clk) { return 1; } | ||
| 33 | static inline void __clk_put(struct clk *clk) { } | 29 | static inline void __clk_put(struct clk *clk) { } |
| 34 | 30 | ||
| 35 | #endif | 31 | #endif |
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 9ab3db8b3988..bdeaffc950ae 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
| @@ -174,16 +174,9 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) | |||
| 174 | if (!cl) | 174 | if (!cl) |
| 175 | goto out; | 175 | goto out; |
| 176 | 176 | ||
| 177 | clk = __clk_create_clk(cl->clk_hw, dev_id, con_id); | 177 | clk = clk_hw_create_clk(cl->clk_hw, dev_id, con_id); |
| 178 | if (IS_ERR(clk)) | 178 | if (IS_ERR(clk)) |
| 179 | goto out; | ||
| 180 | |||
| 181 | if (!__clk_get(clk)) { | ||
| 182 | __clk_free_clk(clk); | ||
| 183 | cl = NULL; | 179 | cl = NULL; |
| 184 | goto out; | ||
| 185 | } | ||
| 186 | |||
| 187 | out: | 180 | out: |
| 188 | mutex_unlock(&clocks_mutex); | 181 | mutex_unlock(&clocks_mutex); |
| 189 | 182 | ||
