Lines Matching +full:min +full:- +full:div
1 // SPDX-License-Identifier: GPL-2.0+
9 #include <linux/clk-provider.h>
47 u8 div; member
78 freq = parent_rate * (frac->mul + 1) + in sam9x60_frac_pll_recalc_rate()
79 DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22)); in sam9x60_frac_pll_recalc_rate()
81 if (core->layout->div2) in sam9x60_frac_pll_recalc_rate()
90 struct regmap *regmap = core->regmap; in sam9x60_frac_pll_set()
94 spin_lock_irqsave(core->lock, flags); in sam9x60_frac_pll_set()
97 AT91_PMC_PLL_UPDT_ID_MSK, core->id); in sam9x60_frac_pll_set()
99 cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; in sam9x60_frac_pll_set()
100 cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; in sam9x60_frac_pll_set()
102 if (sam9x60_frac_pll_ready(regmap, core->id) && in sam9x60_frac_pll_set()
103 (cmul == frac->mul && cfrac == frac->frac)) in sam9x60_frac_pll_set()
107 if (core->characteristics->upll) in sam9x60_frac_pll_set()
114 (frac->mul << core->layout->mul_shift) | in sam9x60_frac_pll_set()
115 (frac->frac << core->layout->frac_shift)); in sam9x60_frac_pll_set()
117 if (core->characteristics->upll) { in sam9x60_frac_pll_set()
133 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_frac_pll_set()
141 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_frac_pll_set()
143 while (!sam9x60_pll_ready(regmap, core->id)) in sam9x60_frac_pll_set()
147 spin_unlock_irqrestore(core->lock, flags); in sam9x60_frac_pll_set()
162 struct regmap *regmap = core->regmap; in sam9x60_frac_pll_unprepare()
165 spin_lock_irqsave(core->lock, flags); in sam9x60_frac_pll_unprepare()
168 AT91_PMC_PLL_UPDT_ID_MSK, core->id); in sam9x60_frac_pll_unprepare()
172 if (core->characteristics->upll) in sam9x60_frac_pll_unprepare()
178 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_frac_pll_unprepare()
180 spin_unlock_irqrestore(core->lock, flags); in sam9x60_frac_pll_unprepare()
187 return sam9x60_pll_ready(core->regmap, core->id); in sam9x60_frac_pll_is_prepared()
200 if (rate < core->characteristics->core_output[0].min || in sam9x60_frac_pll_compute_mul_frac()
201 rate > core->characteristics->core_output[0].max) in sam9x60_frac_pll_compute_mul_frac()
202 return -ERANGE; in sam9x60_frac_pll_compute_mul_frac()
210 remainder = rate - tmprate; in sam9x60_frac_pll_compute_mul_frac()
221 if (tmprate < core->characteristics->core_output[0].min || in sam9x60_frac_pll_compute_mul_frac()
222 tmprate > core->characteristics->core_output[0].max) in sam9x60_frac_pll_compute_mul_frac()
223 return -ERANGE; in sam9x60_frac_pll_compute_mul_frac()
226 frac->mul = nmul - 1; in sam9x60_frac_pll_compute_mul_frac()
227 frac->frac = nfrac; in sam9x60_frac_pll_compute_mul_frac()
254 struct regmap *regmap = core->regmap; in sam9x60_frac_pll_set_rate_chg()
263 spin_lock_irqsave(core->lock, irqflags); in sam9x60_frac_pll_set_rate_chg()
266 core->id); in sam9x60_frac_pll_set_rate_chg()
268 cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; in sam9x60_frac_pll_set_rate_chg()
269 cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; in sam9x60_frac_pll_set_rate_chg()
271 if (cmul == frac->mul && cfrac == frac->frac) in sam9x60_frac_pll_set_rate_chg()
275 (frac->mul << core->layout->mul_shift) | in sam9x60_frac_pll_set_rate_chg()
276 (frac->frac << core->layout->frac_shift)); in sam9x60_frac_pll_set_rate_chg()
280 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_frac_pll_set_rate_chg()
289 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_frac_pll_set_rate_chg()
291 while (!sam9x60_pll_ready(regmap, core->id)) in sam9x60_frac_pll_set_rate_chg()
295 spin_unlock_irqrestore(core->lock, irqflags); in sam9x60_frac_pll_set_rate_chg()
305 frac->pms.status = sam9x60_pll_ready(core->regmap, core->id); in sam9x60_frac_pll_save_context()
315 if (frac->pms.status) in sam9x60_frac_pll_restore_context()
342 static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div, in sam9x60_div_pll_set_div() argument
345 struct regmap *regmap = core->regmap; in sam9x60_div_pll_set_div()
346 u32 ena_msk = enable ? core->layout->endiv_mask : 0; in sam9x60_div_pll_set_div()
347 u32 ena_val = enable ? (1 << core->layout->endiv_shift) : 0; in sam9x60_div_pll_set_div()
350 core->layout->div_mask | ena_msk, in sam9x60_div_pll_set_div()
351 (div << core->layout->div_shift) | ena_val); in sam9x60_div_pll_set_div()
355 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_div_pll_set_div()
357 while (!sam9x60_pll_ready(regmap, core->id)) in sam9x60_div_pll_set_div()
363 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_set() local
364 struct regmap *regmap = core->regmap; in sam9x60_div_pll_set()
368 spin_lock_irqsave(core->lock, flags); in sam9x60_div_pll_set()
370 AT91_PMC_PLL_UPDT_ID_MSK, core->id); in sam9x60_div_pll_set()
372 cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; in sam9x60_div_pll_set()
375 if (!!(val & core->layout->endiv_mask) && cdiv == div->div) in sam9x60_div_pll_set()
378 sam9x60_div_pll_set_div(core, div->div, 1); in sam9x60_div_pll_set()
381 spin_unlock_irqrestore(core->lock, flags); in sam9x60_div_pll_set()
396 struct regmap *regmap = core->regmap; in sam9x60_div_pll_unprepare()
399 spin_lock_irqsave(core->lock, flags); in sam9x60_div_pll_unprepare()
402 AT91_PMC_PLL_UPDT_ID_MSK, core->id); in sam9x60_div_pll_unprepare()
405 core->layout->endiv_mask, 0); in sam9x60_div_pll_unprepare()
409 AT91_PMC_PLL_UPDT_UPDATE | core->id); in sam9x60_div_pll_unprepare()
411 spin_unlock_irqrestore(core->lock, flags); in sam9x60_div_pll_unprepare()
417 struct regmap *regmap = core->regmap; in sam9x60_div_pll_is_prepared()
421 spin_lock_irqsave(core->lock, flags); in sam9x60_div_pll_is_prepared()
424 AT91_PMC_PLL_UPDT_ID_MSK, core->id); in sam9x60_div_pll_is_prepared()
427 spin_unlock_irqrestore(core->lock, flags); in sam9x60_div_pll_is_prepared()
429 return !!(val & core->layout->endiv_mask); in sam9x60_div_pll_is_prepared()
436 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_recalc_rate() local
438 return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1)); in sam9x60_div_pll_recalc_rate()
452 core->characteristics; in sam9x60_div_pll_compute_div()
453 struct clk_hw *parent = clk_hw_get_parent(&core->hw); in sam9x60_div_pll_compute_div()
455 long best_diff = -1, best_rate = -EINVAL; in sam9x60_div_pll_compute_div()
461 if (rate < characteristics->output[0].min || in sam9x60_div_pll_compute_div()
462 rate > characteristics->output[0].max) in sam9x60_div_pll_compute_div()
463 return -ERANGE; in sam9x60_div_pll_compute_div()
465 for (divid = 1; divid < core->layout->div_mask; divid++) { in sam9x60_div_pll_compute_div()
471 tmp_diff = abs(rate - tmp_rate); in sam9x60_div_pll_compute_div()
483 if (best_rate < characteristics->output[0].min || in sam9x60_div_pll_compute_div()
484 best_rate > characteristics->output[0].max) in sam9x60_div_pll_compute_div()
485 return -ERANGE; in sam9x60_div_pll_compute_div()
502 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_set_rate() local
504 div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1; in sam9x60_div_pll_set_rate()
513 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_set_rate_chg() local
514 struct regmap *regmap = core->regmap; in sam9x60_div_pll_set_rate_chg()
518 div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1; in sam9x60_div_pll_set_rate_chg()
520 spin_lock_irqsave(core->lock, irqflags); in sam9x60_div_pll_set_rate_chg()
522 core->id); in sam9x60_div_pll_set_rate_chg()
524 cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; in sam9x60_div_pll_set_rate_chg()
527 if (cdiv == div->div) in sam9x60_div_pll_set_rate_chg()
530 sam9x60_div_pll_set_div(core, div->div, 0); in sam9x60_div_pll_set_rate_chg()
533 spin_unlock_irqrestore(core->lock, irqflags); in sam9x60_div_pll_set_rate_chg()
541 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_save_context() local
543 div->pms.status = sam9x60_div_pll_is_prepared(hw); in sam9x60_div_pll_save_context()
551 struct sam9x60_div *div = to_sam9x60_div(core); in sam9x60_div_pll_restore_context() local
553 if (div->pms.status) in sam9x60_div_pll_restore_context()
560 struct sam9x60_div *div = notifier_div; in sam9x60_div_pll_notifier_fn() local
561 struct sam9x60_pll_core core = div->core; in sam9x60_div_pll_notifier_fn()
574 div->div = div->safe_div; in sam9x60_div_pll_notifier_fn()
580 cdiv = (val & core.layout->div_mask) >> core.layout->div_shift; in sam9x60_div_pll_notifier_fn()
583 if (cdiv == div->safe_div) in sam9x60_div_pll_notifier_fn()
586 sam9x60_div_pll_set_div(&core, div->div, 0); in sam9x60_div_pll_notifier_fn()
646 return ERR_PTR(-EINVAL); in sam9x60_clk_register_frac_pll()
650 return ERR_PTR(-ENOMEM); in sam9x60_clk_register_frac_pll()
665 frac->core.id = id; in sam9x60_clk_register_frac_pll()
666 frac->core.hw.init = &init; in sam9x60_clk_register_frac_pll()
667 frac->core.characteristics = characteristics; in sam9x60_clk_register_frac_pll()
668 frac->core.layout = layout; in sam9x60_clk_register_frac_pll()
669 frac->core.regmap = regmap; in sam9x60_clk_register_frac_pll()
670 frac->core.lock = lock; in sam9x60_clk_register_frac_pll()
672 spin_lock_irqsave(frac->core.lock, irqflags); in sam9x60_clk_register_frac_pll()
677 frac->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); in sam9x60_clk_register_frac_pll()
678 frac->frac = FIELD_GET(PMC_PLL_CTRL1_FRACR_MSK, val); in sam9x60_clk_register_frac_pll()
689 hw = ERR_PTR(-EINVAL); in sam9x60_clk_register_frac_pll()
693 ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, in sam9x60_clk_register_frac_pll()
694 characteristics->core_output[0].min, in sam9x60_clk_register_frac_pll()
701 spin_unlock_irqrestore(frac->core.lock, irqflags); in sam9x60_clk_register_frac_pll()
703 hw = &frac->core.hw; in sam9x60_clk_register_frac_pll()
713 spin_unlock_irqrestore(frac->core.lock, irqflags); in sam9x60_clk_register_frac_pll()
726 struct sam9x60_div *div; in sam9x60_clk_register_div_pll() local
735 return ERR_PTR(-EINVAL); in sam9x60_clk_register_div_pll()
738 safe_div = PLL_DIV_MAX - 1; in sam9x60_clk_register_div_pll()
740 div = kzalloc(sizeof(*div), GFP_KERNEL); in sam9x60_clk_register_div_pll()
741 if (!div) in sam9x60_clk_register_div_pll()
742 return ERR_PTR(-ENOMEM); in sam9x60_clk_register_div_pll()
751 if (layout->div2) in sam9x60_clk_register_div_pll()
760 div->core.id = id; in sam9x60_clk_register_div_pll()
761 div->core.hw.init = &init; in sam9x60_clk_register_div_pll()
762 div->core.characteristics = characteristics; in sam9x60_clk_register_div_pll()
763 div->core.layout = layout; in sam9x60_clk_register_div_pll()
764 div->core.regmap = regmap; in sam9x60_clk_register_div_pll()
765 div->core.lock = lock; in sam9x60_clk_register_div_pll()
766 div->safe_div = safe_div; in sam9x60_clk_register_div_pll()
768 spin_lock_irqsave(div->core.lock, irqflags); in sam9x60_clk_register_div_pll()
773 div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); in sam9x60_clk_register_div_pll()
775 spin_unlock_irqrestore(div->core.lock, irqflags); in sam9x60_clk_register_div_pll()
777 hw = &div->core.hw; in sam9x60_clk_register_div_pll()
780 kfree(div); in sam9x60_clk_register_div_pll()
782 } else if (div->safe_div) { in sam9x60_clk_register_div_pll()
783 notifier_div = div; in sam9x60_clk_register_div_pll()
784 clk_notifier_register(hw->clk, &sam9x60_div_pll_notifier); in sam9x60_clk_register_div_pll()