summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Muellner <christoph.muellner@theobroma-systems.com>2015-05-05 23:27:59 +0200
committerKlaus Goger <klaus.goger@theobroma-systems.com>2015-07-30 18:52:58 +0200
commit836ccda884608f91b4ff57afb3ff2359911343dd (patch)
tree7e5b89c108e10602f009dfcabb17e49724106fad
parent49a2157199999c397262757a302fea80b42dd3fb (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.c54
-rw-r--r--drivers/clk/sunxi/clk-factors.h2
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 {