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>
This commit is contained in:
parent
cfa6368860
commit
435b7be1d8
|
@ -63,6 +63,26 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
|
||||||
if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
||||||
p = FACTOR_GET(config->pshift, config->pwidth, reg);
|
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 */
|
/* Calculate the rate */
|
||||||
rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1);
|
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,
|
static int clk_factors_determine_rate(struct clk_hw *hw,
|
||||||
struct clk_rate_request *req)
|
struct clk_rate_request *req)
|
||||||
{
|
{
|
||||||
|
struct clk_factors *factors = to_clk_factors(hw);
|
||||||
struct clk_hw *parent, *best_parent = NULL;
|
struct clk_hw *parent, *best_parent = NULL;
|
||||||
int i, num_parents;
|
int i, num_parents;
|
||||||
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
|
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 */
|
/* find the parent that can help provide the fastest rate <= rate */
|
||||||
num_parents = clk_hw_get_num_parents(hw);
|
num_parents = clk_hw_get_num_parents(hw);
|
||||||
for (i = 0; i < num_parents; i++) {
|
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);
|
parent = clk_hw_get_parent_by_index(hw, i);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
continue;
|
continue;
|
||||||
|
@ -102,8 +127,9 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
|
||||||
else
|
else
|
||||||
parent_rate = clk_hw_get_rate(parent);
|
parent_rate = clk_hw_get_rate(parent);
|
||||||
|
|
||||||
child_rate = clk_factors_round_rate(hw, req->rate,
|
factors_req.parent_rate = parent_rate;
|
||||||
&parent_rate);
|
factors->get_factors(&factors_req);
|
||||||
|
child_rate = factors_req.rate;
|
||||||
|
|
||||||
if (child_rate <= req->rate && child_rate > best_child_rate) {
|
if (child_rate <= req->rate && child_rate > best_child_rate) {
|
||||||
best_parent = parent;
|
best_parent = parent;
|
||||||
|
@ -202,6 +228,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
|
||||||
factors->reg = reg;
|
factors->reg = reg;
|
||||||
factors->config = data->table;
|
factors->config = data->table;
|
||||||
factors->get_factors = data->getter;
|
factors->get_factors = data->getter;
|
||||||
|
factors->recalc = data->recalc;
|
||||||
factors->lock = lock;
|
factors->lock = lock;
|
||||||
|
|
||||||
/* Add a gate if this factor clock can be gated */
|
/* Add a gate if this factor clock can be gated */
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct clk_factors_config {
|
||||||
struct factors_request {
|
struct factors_request {
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
unsigned long parent_rate;
|
unsigned long parent_rate;
|
||||||
|
u8 parent_index;
|
||||||
u8 n;
|
u8 n;
|
||||||
u8 k;
|
u8 k;
|
||||||
u8 m;
|
u8 m;
|
||||||
|
@ -34,6 +35,7 @@ struct factors_data {
|
||||||
int muxmask;
|
int muxmask;
|
||||||
const struct clk_factors_config *table;
|
const struct clk_factors_config *table;
|
||||||
void (*getter)(struct factors_request *req);
|
void (*getter)(struct factors_request *req);
|
||||||
|
void (*recalc)(struct factors_request *req);
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,6 +44,7 @@ struct clk_factors {
|
||||||
void __iomem *reg;
|
void __iomem *reg;
|
||||||
const struct clk_factors_config *config;
|
const struct clk_factors_config *config;
|
||||||
void (*get_factors)(struct factors_request *req);
|
void (*get_factors)(struct factors_request *req);
|
||||||
|
void (*recalc)(struct factors_request *req);
|
||||||
spinlock_t *lock;
|
spinlock_t *lock;
|
||||||
/* for cleanup */
|
/* for cleanup */
|
||||||
struct clk_mux *mux;
|
struct clk_mux *mux;
|
||||||
|
|
Loading…
Reference in New Issue