From 119c71276b43e3daf5e7b0661dcf63f224e2fc8d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 3 Oct 2012 23:38:53 -0700 Subject: clk: Document .is_enabled op Add the missing kernel-doc for this op. Signed-off-by: Stephen Boyd Signed-off-by: Mike Turquette --- include/linux/clk-provider.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux/clk-provider.h') diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index c12731582920..2aa808bdc257 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -53,6 +53,10 @@ struct clk_hw; * @disable: Disable the clock atomically. Called with enable_lock held. * This function must not sleep. * + * @is_enabled: Queries the hardware to determine if the clock is enabled. + * This function must not sleep. Optional, if this op is not + * set then the enable count will be used. + * * @recalc_rate Recalculate the rate of this clock, by quering hardware. The * parent rate is an input parameter. It is up to the caller to * insure that the prepare_mutex is held across this call. -- cgit v1.2.3 From 7ce3e8ccbac708229ba8c40c9c2a43ca7fcdb3ae Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 3 Oct 2012 23:38:54 -0700 Subject: clk: Fix documentation typos Fix some minor typos in the documentation for the ops structure. Signed-off-by: Stephen Boyd Signed-off-by: Mike Turquette --- include/linux/clk-provider.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux/clk-provider.h') diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2aa808bdc257..e1d83b187df2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -57,9 +57,9 @@ struct clk_hw; * This function must not sleep. Optional, if this op is not * set then the enable count will be used. * - * @recalc_rate Recalculate the rate of this clock, by quering hardware. The + * @recalc_rate Recalculate the rate of this clock, by querying hardware. The * parent rate is an input parameter. It is up to the caller to - * insure that the prepare_mutex is held across this call. + * ensure that the prepare_mutex is held across this call. * Returns the calculated rate. Optional, but recommended - if * this op is not set then clock rate will be initialized to 0. * @@ -93,7 +93,7 @@ struct clk_hw; * implementations to split any work between atomic (enable) and sleepable * (prepare) contexts. If enabling a clock requires code that might sleep, * this must be done in clk_prepare. Clock enable code that will never be - * called in a sleepable context may be implement in clk_enable. + * called in a sleepable context may be implemented in clk_enable. * * Typically, drivers will call clk_prepare when a clock may be needed later * (eg. when a device is opened), and clk_enable when the clock is actually -- cgit v1.2.3 From 2ac6b1f50a397580b8dc28f2833e54af7926fc71 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 3 Oct 2012 23:38:55 -0700 Subject: clk: Don't return negative numbers for unsigned values with !clk Some of the helper functions return negative error codes if passed a NULL clock. This can lead to confusing behavior when the expected return value is unsigned. Fix up these accessors so that they return unsigned values (or bool in the case of is_enabled). This way we can't interpret NULL clocks as having valid and interesting values. Signed-off-by: Stephen Boyd Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 20 ++++++++++---------- include/linux/clk-provider.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux/clk-provider.h') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 56e4495ebeb1..bbe52c4ae7ca 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -261,7 +261,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk) inline u8 __clk_get_num_parents(struct clk *clk) { - return !clk ? -EINVAL : clk->num_parents; + return !clk ? 0 : clk->num_parents; } inline struct clk *__clk_get_parent(struct clk *clk) @@ -269,14 +269,14 @@ inline struct clk *__clk_get_parent(struct clk *clk) return !clk ? NULL : clk->parent; } -inline int __clk_get_enable_count(struct clk *clk) +inline unsigned int __clk_get_enable_count(struct clk *clk) { - return !clk ? -EINVAL : clk->enable_count; + return !clk ? 0 : clk->enable_count; } -inline int __clk_get_prepare_count(struct clk *clk) +inline unsigned int __clk_get_prepare_count(struct clk *clk) { - return !clk ? -EINVAL : clk->prepare_count; + return !clk ? 0 : clk->prepare_count; } unsigned long __clk_get_rate(struct clk *clk) @@ -302,15 +302,15 @@ out: inline unsigned long __clk_get_flags(struct clk *clk) { - return !clk ? -EINVAL : clk->flags; + return !clk ? 0 : clk->flags; } -int __clk_is_enabled(struct clk *clk) +bool __clk_is_enabled(struct clk *clk) { int ret; if (!clk) - return -EINVAL; + return false; /* * .is_enabled is only mandatory for clocks that gate @@ -323,7 +323,7 @@ int __clk_is_enabled(struct clk *clk) ret = clk->ops->is_enabled(clk->hw); out: - return ret; + return !!ret; } static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) @@ -568,7 +568,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) unsigned long parent_rate = 0; if (!clk) - return -EINVAL; + return 0; if (!clk->ops->round_rate) { if (clk->flags & CLK_SET_RATE_PARENT) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index e1d83b187df2..0dce3d31eae5 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -339,11 +339,11 @@ const char *__clk_get_name(struct clk *clk); struct clk_hw *__clk_get_hw(struct clk *clk); u8 __clk_get_num_parents(struct clk *clk); struct clk *__clk_get_parent(struct clk *clk); -inline int __clk_get_enable_count(struct clk *clk); -inline int __clk_get_prepare_count(struct clk *clk); +inline unsigned int __clk_get_enable_count(struct clk *clk); +inline unsigned int __clk_get_prepare_count(struct clk *clk); unsigned long __clk_get_rate(struct clk *clk); unsigned long __clk_get_flags(struct clk *clk); -int __clk_is_enabled(struct clk *clk); +bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); /* -- cgit v1.2.3 From 46c8773a58010d31f228e148b8b774d94cc9810d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 24 Sep 2012 13:38:04 -0700 Subject: clk: Add devm_clk_{register,unregister}() Some clock drivers can be simplified if devres takes care of unregistering any registered clocks along error paths. Introduce devm_clk_register() so that clock drivers get unregistration for free along with simplified error paths. Signed-off-by: Stephen Boyd Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 111 +++++++++++++++++++++++++++++++++++-------- include/linux/clk-provider.h | 2 + 2 files changed, 92 insertions(+), 21 deletions(-) (limited to 'include/linux/clk-provider.h') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index bbe52c4ae7ca..2fd28ddd06c9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -17,6 +17,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); @@ -1361,28 +1362,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) } EXPORT_SYMBOL_GPL(__clk_register); -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) +static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) { int i, ret; - struct clk *clk; - - clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) { - pr_err("%s: could not allocate clk\n", __func__); - ret = -ENOMEM; - goto fail_out; - } clk->name = kstrdup(hw->init->name, GFP_KERNEL); if (!clk->name) { @@ -1420,7 +1402,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ret = __clk_init(dev, clk); if (!ret) - return clk; + return 0; fail_parent_names_copy: while (--i >= 0) @@ -1429,6 +1411,36 @@ fail_parent_names_copy: fail_parent_names: kfree(clk->name); fail_name: + return ret; +} + +/** + * clk_register - allocate a new clock, register it and return an opaque cookie + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_register is the primary interface for populating the clock tree with new + * clock nodes. It returns a pointer to the newly allocated struct clk which + * cannot be dereferenced by driver code but may be used in conjuction with the + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. + */ +struct clk *clk_register(struct device *dev, struct clk_hw *hw) +{ + int ret; + struct clk *clk; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + pr_err("%s: could not allocate clk\n", __func__); + ret = -ENOMEM; + goto fail_out; + } + + ret = _clk_register(dev, hw, clk); + if (!ret) + return clk; + kfree(clk); fail_out: return ERR_PTR(ret); @@ -1444,6 +1456,63 @@ EXPORT_SYMBOL_GPL(clk_register); void clk_unregister(struct clk *clk) {} EXPORT_SYMBOL_GPL(clk_unregister); +static void devm_clk_release(struct device *dev, void *res) +{ + clk_unregister(res); +} + +/** + * devm_clk_register - resource managed clk_register() + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * Managed clk_register(). Clocks returned from this function are + * automatically clk_unregister()ed on driver detach. See clk_register() for + * more information. + */ +struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) +{ + struct clk *clk; + int ret; + + clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + ret = _clk_register(dev, hw, clk); + if (!ret) { + devres_add(dev, clk); + } else { + devres_free(clk); + clk = ERR_PTR(ret); + } + + return clk; +} +EXPORT_SYMBOL_GPL(devm_clk_register); + +static int devm_clk_match(struct device *dev, void *res, void *data) +{ + struct clk *c = res; + if (WARN_ON(!c)) + return 0; + return c == data; +} + +/** + * devm_clk_unregister - resource managed clk_unregister() + * @clk: clock to unregister + * + * Deallocate a clock allocated with devm_clk_register(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_clk_unregister(struct device *dev, struct clk *clk) +{ + WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk)); +} +EXPORT_SYMBOL_GPL(devm_clk_unregister); + /*** clk rate change notifiers ***/ /** diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 0dce3d31eae5..3593a3ce3f0d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -331,8 +331,10 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, * error code; drivers must test for an error code after calling clk_register. */ struct clk *clk_register(struct device *dev, struct clk_hw *hw); +struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw); void clk_unregister(struct clk *clk); +void devm_clk_unregister(struct device *dev, struct clk *clk); /* helper functions */ const char *__clk_get_name(struct clk *clk); -- cgit v1.2.3 From 7c045a55c97fb83a2e5e9c6c857162c4866cc602 Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Tue, 4 Dec 2012 11:00:35 -0800 Subject: clk: introduce optional disable_unused callback Some gate clocks have special needs which must be handled during the disable-unused clocks sequence. These needs might be driven by software due to the fact that we're disabling a clock outside of the normal clk_disable path and a clk's enable_count will not be accurate. On the other hand a specific hardware programming sequence might need to be followed for this corner case. This change is needed for the upcoming OMAP port to the common clock framework. Specifically, it is undesirable to treat the disable-unused path identically to the normal clk_disable path since other software layers are involved. In this case OMAP's clockdomain code throws WARNs and bails early due to the clock's enable_count being set to zero. A custom callback mitigates this problem nicely. Cc: Paul Walmsley Acked-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 13 +++++++++++-- include/linux/clk-provider.h | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'include/linux/clk-provider.h') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9955ad7e786e..251e45d6024d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -219,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk) if (clk->flags & CLK_IGNORE_UNUSED) goto unlock_out; - if (__clk_is_enabled(clk) && clk->ops->disable) - clk->ops->disable(clk->hw); + /* + * some gate clocks have special needs during the disable-unused + * sequence. call .disable_unused if available, otherwise fall + * back to .disable + */ + if (__clk_is_enabled(clk)) { + if (clk->ops->disable_unused) + clk->ops->disable_unused(clk->hw); + else if (clk->ops->disable) + clk->ops->disable(clk->hw); + } unlock_out: spin_unlock_irqrestore(&enable_lock, flags); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 3593a3ce3f0d..1c94d18514e2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -57,6 +57,11 @@ struct clk_hw; * This function must not sleep. Optional, if this op is not * set then the enable count will be used. * + * @disable_unused: Disable the clock atomically. Only called from + * clk_disable_unused for gate clocks with special needs. + * Called with enable_lock held. This function must not + * sleep. + * * @recalc_rate Recalculate the rate of this clock, by querying hardware. The * parent rate is an input parameter. It is up to the caller to * ensure that the prepare_mutex is held across this call. @@ -106,6 +111,7 @@ struct clk_ops { int (*enable)(struct clk_hw *hw); void (*disable)(struct clk_hw *hw); int (*is_enabled)(struct clk_hw *hw); + void (*disable_unused)(struct clk_hw *hw); unsigned long (*recalc_rate)(struct clk_hw *hw, unsigned long parent_rate); long (*round_rate)(struct clk_hw *hw, unsigned long, -- cgit v1.2.3