diff options
Diffstat (limited to 'drivers/clk/at91/clk-sam9x60-pll.c')
-rw-r--r-- | drivers/clk/at91/clk-sam9x60-pll.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index ff65f7b916f0..fda041102224 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -23,9 +23,6 @@ #define UPLL_DIV 2 #define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) -#define FCORE_MIN (600000000) -#define FCORE_MAX (1200000000) - #define PLL_MAX_ID 7 struct sam9x60_pll_core { @@ -76,9 +73,15 @@ static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw, { struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); struct sam9x60_frac *frac = to_sam9x60_frac(core); + unsigned long freq; - return parent_rate * (frac->mul + 1) + + freq = parent_rate * (frac->mul + 1) + DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22)); + + if (core->layout->div2) + freq >>= 1; + + return freq; } static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core) @@ -194,7 +197,8 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core, unsigned long nmul = 0; unsigned long nfrac = 0; - if (rate < FCORE_MIN || rate > FCORE_MAX) + if (rate < core->characteristics->core_output[0].min || + rate > core->characteristics->core_output[0].max) return -ERANGE; /* @@ -214,7 +218,8 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core, } /* Check if resulted rate is a valid. */ - if (tmprate < FCORE_MIN || tmprate > FCORE_MAX) + if (tmprate < core->characteristics->core_output[0].min || + tmprate > core->characteristics->core_output[0].max) return -ERANGE; if (update) { @@ -433,6 +438,12 @@ static unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1)); } +static unsigned long sam9x60_fixed_div_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate >> 1; +} + static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core, unsigned long *parent_rate, unsigned long rate) @@ -607,6 +618,16 @@ static const struct clk_ops sam9x60_div_pll_ops_chg = { .restore_context = sam9x60_div_pll_restore_context, }; +static const struct clk_ops sam9x60_fixed_div_pll_ops = { + .prepare = sam9x60_div_pll_prepare, + .unprepare = sam9x60_div_pll_unprepare, + .is_prepared = sam9x60_div_pll_is_prepared, + .recalc_rate = sam9x60_fixed_div_pll_recalc_rate, + .round_rate = sam9x60_div_pll_round_rate, + .save_context = sam9x60_div_pll_save_context, + .restore_context = sam9x60_div_pll_restore_context, +}; + struct clk_hw * __init sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, @@ -669,7 +690,8 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, goto free; } - ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN, + ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, + characteristics->core_output[0].min, parent_rate, true); if (ret < 0) { hw = ERR_PTR(ret); @@ -725,10 +747,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, else init.parent_names = &parent_name; init.num_parents = 1; - if (flags & CLK_SET_RATE_GATE) + + if (layout->div2) + init.ops = &sam9x60_fixed_div_pll_ops; + else if (flags & CLK_SET_RATE_GATE) init.ops = &sam9x60_div_pll_ops; else init.ops = &sam9x60_div_pll_ops_chg; + init.flags = flags; div->core.id = id; |