From 4ba2917a97d8b1264681d2ca92b2276d421af7c1 Mon Sep 17 00:00:00 2001 From: Alex Frid Date: Tue, 7 Feb 2017 14:04:44 -0800 Subject: [PATCH] clk: Add parent change notifications Added parent change notifications to be used when drivers behavior depends on physical nature of the parent, not just clock rate it supplies (e.g., selection of Tegra DFLL as CPU clock source changes mechanism of voltage control even if the clock rate stays the same as on PLL). Bug 200269751 Change-Id: I617c94927ef437caf240efd91497b49ad6f5c39d Signed-off-by: Alex Frid Reviewed-on: https://git-master.nvidia.com/r/1573111 Reviewed-by: svc-mobile-coverity Reviewed-by: svccoveritychecker Reviewed-by: Peter De Schrijver Tested-by: Peter De Schrijver GVS: Gerrit_Virtual_Submit Reviewed-by: Sachin Nikam Reviewed-by: Timo Alho Signed-off-by: Thomas Makin --- drivers/clk/clk.c | 15 +++++++++++++-- include/linux/clk.h | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 886718dc83e6..10bea7a838f0 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2880,6 +2880,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core, int ret = 0; int p_index = 0; unsigned long p_rate = 0; + unsigned long old_p_rate = 0; lockdep_assert_held(&prepare_lock); @@ -2922,13 +2923,23 @@ static int clk_core_set_parent_nolock(struct clk_core *core, if (ret & NOTIFY_STOP_MASK) goto runtime_put; - /* do the re-parent */ - ret = __clk_set_parent(core, parent, p_index); + + /* propagate PRE_PARENT_CHANGE notifications */ + if (core->parent) + old_p_rate = core->parent->rate; + + ret = __clk_notify(core, PRE_PARENT_CHANGE, old_p_rate, p_rate); + + /* do the re-parent if no objections */ + if (!(ret & NOTIFY_STOP_MASK)) + ret = __clk_set_parent(core, parent, p_index); /* propagate rate an accuracy recalculation accordingly */ if (ret) { + __clk_notify(core, ABORT_PARENT_CHANGE, old_p_rate, p_rate); __clk_recalc_rates(core, true, ABORT_RATE_CHANGE); } else { + __clk_notify(core, POST_PARENT_CHANGE, old_p_rate, p_rate); __clk_recalc_rates(core, true, POST_RATE_CHANGE); __clk_recalc_accuracies(core); } diff --git a/include/linux/clk.h b/include/linux/clk.h index 09064fcd4c76..68f0aec106e9 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -42,12 +42,26 @@ struct of_phandle_args; * POST_SUBTREE_UPDATE - called after rate change is propagated down to * sub-tree rooted in clk. Callbacks must always return NOTIFY_DONE * or NOTIFY_OK. + * + * PRE_PARENT_CHANGE - called immediately before the clk parent is changed, + * to indicate that the parent change will proceed. Callbacks may either + * return NOTIFY_DONE, NOTIFY_OK, NOTIFY_STOP or NOTIFY_BAD. + * + * ABORT_PARENT_CHANGE: called if the parent change failed for some reason + * after PRE_PARENT_CHANGE. Callbacks must always return NOTIFY_DONE or + * NOTIFY_OK. + * + * POST_PARENT_CHANGE - called after the clk parent change has successfully + * completed. Callbacks must always return NOTIFY_DONE or NOTIFY_OK. */ #define PRE_RATE_CHANGE BIT(0) #define POST_RATE_CHANGE BIT(1) #define ABORT_RATE_CHANGE BIT(2) #define PRE_SUBTREE_CHANGE BIT(3) #define POST_SUBTREE_CHANGE BIT(4) +#define PRE_PARENT_CHANGE BIT(5) +#define POST_PARENT_CHANGE BIT(6) +#define ABORT_PARENT_CHANGE BIT(7) /** * struct clk_notifier - associate a clk with a notifier