diff options
author | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2015-05-05 23:27:59 +0200 |
---|---|---|
committer | Klaus Goger <klaus.goger@theobroma-systems.com> | 2015-07-30 18:52:58 +0200 |
commit | 836ccda884608f91b4ff57afb3ff2359911343dd (patch) | |
tree | 7e5b89c108e10602f009dfcabb17e49724106fad | |
parent | 49a2157199999c397262757a302fea80b42dd3fb (diff) |
Clk: Sunxi: Add support for reparenting.
This patch adds support for reparenting sunxi factor clocks.
The idea is simple: if the DTS provides all possible
parents in the correct order, they can be tagged by
"clocks-complete" = "ok";
If such a property is found in a sunxi factor clock, then
the reparenting uses the indices of the parent list provided
in the DTB and the new clock properties parentwidth and parentshift
to set the new parent in the clock configuration register.
Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
-rw-r--r-- | drivers/clk/sunxi/clk-factors.c | 54 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.h | 2 |
2 files changed, 55 insertions, 1 deletions
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 8c20190a3e9f..2b0ef1613c84 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -151,6 +151,38 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static u8 clk_factors_get_parent(struct clk_hw *hw) +{ + struct clk_factors *factors = to_clk_factors(hw); + struct clk_factors_config *config = factors->config; + u32 reg; + + reg = readl(factors->reg); + return FACTOR_GET(config->parentshift, config->parentwidth, reg); +} + +static int clk_factors_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_factors *factors = to_clk_factors(hw); + struct clk_factors_config *config = factors->config; + unsigned long flags = 0; + u32 reg; + + if (factors->lock) + spin_lock_irqsave(factors->lock, flags); + + reg = readl(factors->reg); + + reg = FACTOR_SET(config->parentshift, config->parentwidth, reg, index); + + writel(reg, factors->reg); + + if (factors->lock) + spin_unlock_irqrestore(factors->lock, flags); + + return 0; +} + static const struct clk_ops clk_factors_ops = { .determine_rate = clk_factors_determine_rate, .recalc_rate = clk_factors_recalc_rate, @@ -158,6 +190,15 @@ static const struct clk_ops clk_factors_ops = { .set_rate = clk_factors_set_rate, }; +static const struct clk_ops clk_factors_with_parenting_ops = { + .determine_rate = clk_factors_determine_rate, + .recalc_rate = clk_factors_recalc_rate, + .round_rate = clk_factors_round_rate, + .set_rate = clk_factors_set_rate, + .get_parent = clk_factors_get_parent, + .set_parent = clk_factors_set_parent, +}; + struct clk *sunxi_factors_register(struct device_node *node, const struct factors_data *data, spinlock_t *lock, @@ -171,6 +212,7 @@ struct clk *sunxi_factors_register(struct device_node *node, struct clk_hw *mux_hw = NULL; const char *clk_name = node->name; const char *parents[FACTORS_MAX_PARENTS]; + const struct clk_ops *clk_ops; int i = 0; /* if we have a mux, we will have >1 parents */ @@ -229,10 +271,20 @@ struct clk *sunxi_factors_register(struct device_node *node, mux_hw = &mux->hw; } + /* Some clocks specify all their possible parents + * in correct order in the DTB. + * We accept reparenting on them. + */ + if (of_property_match_string(node, "clocks-complete", "okay") > 0 || + of_property_match_string(node, "clocks-complete", "ok") > 0) + clk_ops = &clk_factors_with_parenting_ops; + else + clk_ops = &clk_factors_ops; + clk = clk_register_composite(NULL, clk_name, parents, i, mux_hw, &clk_mux_ops, - &factors->hw, &clk_factors_ops, + &factors->hw, clk_ops, gate_hw, &clk_gate_ops, 0); if (!IS_ERR(clk)) { diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index 171085ab5513..1fee3d096738 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h @@ -17,6 +17,8 @@ struct clk_factors_config { u8 pshift; u8 pwidth; u8 n_start; + u8 parentshift; + u8 parentwidth; }; struct factors_data { |