Lines Matching +full:divider +full:- +full:offset
1 // SPDX-License-Identifier: GPL-2.0-or-later
6 #include <linux/clk-provider.h>
20 #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \
21 (layout)->mul_mask)
23 #define PLL_MUL_MASK(layout) ((layout)->mul_mask)
58 struct regmap *regmap = pll->regmap; in clk_pll_prepare()
59 const struct clk_pll_layout *layout = pll->layout; in clk_pll_prepare()
61 pll->characteristics; in clk_pll_prepare()
62 u8 id = pll->id; in clk_pll_prepare()
64 int offset = PLL_REG(id); in clk_pll_prepare() local
71 regmap_read(regmap, offset, &pllr); in clk_pll_prepare()
77 (div == pll->div && mul == pll->mul)) in clk_pll_prepare()
80 if (characteristics->out) in clk_pll_prepare()
81 out = characteristics->out[pll->range]; in clk_pll_prepare()
83 if (characteristics->icpll) in clk_pll_prepare()
85 characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id)); in clk_pll_prepare()
87 regmap_update_bits(regmap, offset, layout->pllr_mask, in clk_pll_prepare()
88 pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | in clk_pll_prepare()
90 ((pll->mul & layout->mul_mask) << layout->mul_shift)); in clk_pll_prepare()
92 while (!clk_pll_ready(regmap, pll->id)) in clk_pll_prepare()
102 return clk_pll_ready(pll->regmap, pll->id); in clk_pll_is_prepared()
108 unsigned int mask = pll->layout->pllr_mask; in clk_pll_unprepare()
110 regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask); in clk_pll_unprepare()
118 if (!pll->div || !pll->mul) in clk_pll_recalc_rate()
121 return (parent_rate / pll->div) * (pll->mul + 1); in clk_pll_recalc_rate()
128 const struct clk_pll_layout *layout = pll->layout; in clk_pll_get_best_div_mul()
130 pll->characteristics; in clk_pll_get_best_div_mul()
133 long bestrate = -ERANGE; in clk_pll_get_best_div_mul()
139 if (parent_rate < characteristics->input.min) in clk_pll_get_best_div_mul()
140 return -ERANGE; in clk_pll_get_best_div_mul()
143 * Calculate minimum divider based on the minimum multiplier, the in clk_pll_get_best_div_mul()
152 if (parent_rate > characteristics->input.max) { in clk_pll_get_best_div_mul()
153 tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max); in clk_pll_get_best_div_mul()
155 return -ERANGE; in clk_pll_get_best_div_mul()
162 * Calculate the maximum divider which is limited by PLL register in clk_pll_get_best_div_mul()
170 * Iterate over the acceptable divider values to find the best in clk_pll_get_best_div_mul()
171 * divider/multiplier pair (the one that generates the closest in clk_pll_get_best_div_mul()
181 * divider that provide the closest rate to the requested one. in clk_pll_get_best_div_mul()
186 remainder = tmprate - rate; in clk_pll_get_best_div_mul()
188 remainder = rate - tmprate; in clk_pll_get_best_div_mul()
192 * now and elect a new best multiplier/divider pair if the in clk_pll_get_best_div_mul()
204 * Stop searching now and use this multiplier/divider pair. in clk_pll_get_best_div_mul()
210 /* We haven't found any multiplier/divider pair => return -ERANGE */ in clk_pll_get_best_div_mul()
215 for (i = 0; i < characteristics->num_output; i++) { in clk_pll_get_best_div_mul()
216 if (bestrate >= characteristics->output[i].min && in clk_pll_get_best_div_mul()
217 bestrate <= characteristics->output[i].max) in clk_pll_get_best_div_mul()
221 if (i >= characteristics->num_output) in clk_pll_get_best_div_mul()
222 return -ERANGE; in clk_pll_get_best_div_mul()
227 *mul = bestmul - 1; in clk_pll_get_best_div_mul()
257 pll->range = index; in clk_pll_set_rate()
258 pll->div = div; in clk_pll_set_rate()
259 pll->mul = mul; in clk_pll_set_rate()
269 pll->pms.parent_rate = clk_hw_get_rate(parent_hw); in clk_pll_save_context()
270 pll->pms.rate = clk_pll_recalc_rate(&pll->hw, pll->pms.parent_rate); in clk_pll_save_context()
271 pll->pms.status = clk_pll_ready(pll->regmap, PLL_REG(pll->id)); in clk_pll_save_context()
283 if (pll->characteristics->out) in clk_pll_restore_context()
284 out = pll->characteristics->out[pll->range]; in clk_pll_restore_context()
286 regmap_read(pll->regmap, PLL_REG(pll->id), &pllr); in clk_pll_restore_context()
288 calc_rate = (pll->pms.parent_rate / PLL_DIV(pllr)) * in clk_pll_restore_context()
289 (PLL_MUL(pllr, pll->layout) + 1); in clk_pll_restore_context()
293 if (pll->pms.rate != calc_rate || in clk_pll_restore_context()
294 pll->pms.status != clk_pll_ready(pll->regmap, PLL_REG(pll->id)) || in clk_pll_restore_context()
320 int offset = PLL_REG(id); in at91_clk_register_pll() local
325 return ERR_PTR(-EINVAL); in at91_clk_register_pll()
329 return ERR_PTR(-ENOMEM); in at91_clk_register_pll()
337 pll->id = id; in at91_clk_register_pll()
338 pll->hw.init = &init; in at91_clk_register_pll()
339 pll->layout = layout; in at91_clk_register_pll()
340 pll->characteristics = characteristics; in at91_clk_register_pll()
341 pll->regmap = regmap; in at91_clk_register_pll()
342 regmap_read(regmap, offset, &pllr); in at91_clk_register_pll()
343 pll->div = PLL_DIV(pllr); in at91_clk_register_pll()
344 pll->mul = PLL_MUL(pllr, layout); in at91_clk_register_pll()
346 hw = &pll->hw; in at91_clk_register_pll()
347 ret = clk_hw_register(NULL, &pll->hw); in at91_clk_register_pll()