summaryrefslogtreecommitdiff
path: root/drivers/clk/sunxi/clk-factors.c
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2016-01-25 16:15:43 +0300
committerMaxime Ripard <maxime.ripard@free-electrons.com>2016-01-29 13:30:27 +0300
commit435b7be1d812cdbbad997f5279293770dff21abb (patch)
treefd85027fb06fb90df14872f7fdb54c10d1d60563 /drivers/clk/sunxi/clk-factors.c
parentcfa63688603398e8de4315cd626f81516c88a4c4 (diff)
downloadlinux-435b7be1d812cdbbad997f5279293770dff21abb.tar.xz
clk: sunxi: factors: Support custom formulas
Some clocks cannot be modelled using the standard factors clk formula, such as clocks with special pre-dividers on one parent, or clocks with all power-of-two dividers. Add support for a custom .recalc callback for factors clk. Also pass the current parent index to the .get_factor and .recalc callbacks. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Diffstat (limited to 'drivers/clk/sunxi/clk-factors.c')
-rw-r--r--drivers/clk/sunxi/clk-factors.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 4a8e36a53287..2927b09d5e0d 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -63,6 +63,26 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
p = FACTOR_GET(config->pshift, config->pwidth, reg);
+ if (factors->recalc) {
+ struct factors_request factors_req = {
+ .parent_rate = parent_rate,
+ .n = n,
+ .k = k,
+ .m = m,
+ .p = p,
+ };
+
+ /* get mux details from mux clk structure */
+ if (factors->mux)
+ factors_req.parent_index =
+ (reg >> factors->mux->shift) &
+ factors->mux->mask;
+
+ factors->recalc(&factors_req);
+
+ return factors_req.rate;
+ }
+
/* Calculate the rate */
rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1);
@@ -87,6 +107,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
static int clk_factors_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
+ struct clk_factors *factors = to_clk_factors(hw);
struct clk_hw *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
@@ -94,6 +115,10 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
/* find the parent that can help provide the fastest rate <= rate */
num_parents = clk_hw_get_num_parents(hw);
for (i = 0; i < num_parents; i++) {
+ struct factors_request factors_req = {
+ .rate = req->rate,
+ .parent_index = i,
+ };
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
@@ -102,8 +127,9 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
else
parent_rate = clk_hw_get_rate(parent);
- child_rate = clk_factors_round_rate(hw, req->rate,
- &parent_rate);
+ factors_req.parent_rate = parent_rate;
+ factors->get_factors(&factors_req);
+ child_rate = factors_req.rate;
if (child_rate <= req->rate && child_rate > best_child_rate) {
best_parent = parent;
@@ -202,6 +228,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
factors->reg = reg;
factors->config = data->table;
factors->get_factors = data->getter;
+ factors->recalc = data->recalc;
factors->lock = lock;
/* Add a gate if this factor clock can be gated */