diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 99af6826ac14..5485d87eb92b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2959,6 +2959,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); @@ -3001,13 +3002,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