clk: add support for clock reparent on set_rate
authorJames Hogan <james.hogan@imgtec.com>
Mon, 29 Jul 2013 11:25:00 +0000 (12:25 +0100)
committer黄涛 <huangtao@rock-chips.com>
Wed, 8 Jan 2014 03:03:42 +0000 (11:03 +0800)
commit905377241b5593de5e5830b15454fd95b6f3aa55
tree254c54476692b3f5c3c8b520a01ee4db5e164a78
parent56ec47cc1214e292cb47adabbde9032f18bbd004
clk: add support for clock reparent on set_rate

Add core support to allow clock implementations to select the best
parent clock when rounding a rate, e.g. the one which can provide the
closest clock rate to that requested. This is by way of adding a new
clock op, determine_rate(), which is like round_rate() but has an extra
parameter to allow the clock implementation to optionally select a
different parent clock. The core then takes care of reparenting the
clock when setting the rate.

The parent change takes place with the help of some new private data
members. struct clk::new_parent specifies a clock's new parent (NULL
indicates no change), and struct clk::new_child specifies a clock's new
child (whose new_parent member points back to it). The purpose of these
are to allow correct walking of the future tree for notifications prior
to actually reparenting any clocks, specifically to skip child clocks
who are being reparented to another clock (they will be notified via the
new parent), and to include any new child clock. These pointers are set
by clk_calc_subtree(), and the new_child pointer gets cleared when a
child is actually reparented to avoid duplicate POST_RATE_CHANGE
notifications.

Each place where round_rate() is called, determine_rate() is checked
first and called in preference. This restructures a few of the call
sites to simplify the logic into if/else blocks.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Documentation/clk.txt
drivers/clk/clk.c
include/linux/clk-private.h
include/linux/clk-provider.h