Add the clock notifier infrastructure. The external function exposed here is omap_clk_notify_downstream(). This is intended to be used by architecture-specific clk_set_rate() and clk_set_parent() functions, e.g., omap2_clk_set_rate(). Signed-off-by: Paul Walmsley <paul@xxxxxxxxx> --- arch/arm/plat-omap/clock.c | 81 +++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/mach/clock.h | 1 2 files changed, 82 insertions(+), 0 deletions(-) diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 4c2ed56..73bef03 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -173,6 +173,64 @@ void omap_clk_del_child(struct clk *clk, struct clk *clk2) } } +/** + * omap_clk_notify - call clk notifier chain + * @clk: struct clk * that is changing rate + * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h) + * @old_rate: old rate + * @new_rate: new rate + * + * Triggers a notifier call chain on the post-clk-rate-change notifier + * for clock 'clk'. Passes a pointer to the struct clk and the + * previous and current rates to the notifier callback. Intended to be + * called by internal clock code only. No return value. + */ +static int omap_clk_notify(struct clk *clk, unsigned long msg, + unsigned long old_rate, unsigned long new_rate) +{ + struct clk_notifier *cn; + struct clk_notifier_data cnd; + int ret = NOTIFY_DONE; + + cnd.clk = clk; + cnd.old_rate = old_rate; + cnd.new_rate = new_rate; + + list_for_each_entry(cn, &clk_notifier_list, node) { + if (cn->clk == clk) { + ret = atomic_notifier_call_chain(&cn->notifier_head, + msg, &cnd); + break; + } + } + + return ret; +} + +/** + * _do_clk_notifier - callback function for clock change notification + * @clk: struct clk * to start the notifications with + * @msg: notifier msg - see "Clk notifier callback types" + * @param2: unused + * + * Notify callbacks associated with @clk that a clock change will or has + * occurred. If @msg is CLK_PREPARE_RATE_CHANGE, then actually pay attention + * to the notifier return value. + */ +static int _do_clk_notifier(struct clk *clk, unsigned long msg, u8 param2) +{ + int ret; + + ret = omap_clk_notify(clk, msg, clk->rate, clk->temp_rate); + if (ret && msg == CLK_PREPARE_RATE_CHANGE) + return ret; + + if (omap_clk_has_children(clk)) + return omap_clk_notify_downstream(clk, msg); + else + return 0; +} + /*------------------------------------------------------------------------- * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/ @@ -440,6 +498,27 @@ void recalculate_root_clocks(void) _do_propagate_rate(clkp, 0, CURRENT_RATE); } +/** + * omap_clk_notify_downstream - trigger clock change notifications + * @clk: struct clk * to start the notifications with + * @msg: notifier msg - see "Clk notifier callback types" + * + * Call clock change notifiers on clocks starting with @clk and including + * all of @clk's downstream children clocks. Returns NOTIFY_DONE if + * the notifiers ran successfully, or when msg is CLK_PREPARE_RATE_CHANGE, + * NOTIFY_BAD if one of the notifiers denied the change. + */ +int omap_clk_notify_downstream(struct clk *clk, unsigned long msg) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if (!clk->notifier_count) + return 0; + + return omap_clk_for_each_child(clk, msg, 0, _do_clk_notifier); +} + int clk_register(struct clk *clk) { if (clk == NULL || IS_ERR(clk)) @@ -529,6 +608,8 @@ void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) EXPORT_SYMBOL(clk_init_cpufreq_table); #endif +/* Clk notifier implementations */ + /** * clk_notifier_register - add a clock parameter change notifier * @clk: struct clk * to watch diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h index d08f16c..2faf4c4 100644 --- a/arch/arm/plat-omap/include/mach/clock.h +++ b/arch/arm/plat-omap/include/mach/clock.h @@ -183,6 +183,7 @@ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); #endif void omap_clk_add_child(struct clk *clk, struct clk *clk2); void omap_clk_del_child(struct clk *clk, struct clk *clk2); +extern int omap_clk_notify_downstream(struct clk *clk, unsigned long msg); /* Clock flags */ #define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */ -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html