Lines Matching +full:pll +full:- +full:out
1 // SPDX-License-Identifier: GPL-2.0
3 * Sophgo SG2042 PLL clock Driver
12 #include <linux/clk-provider.h>
18 #include <dt-bindings/clock/sophgo,sg2042-pll.h>
20 #include "clk-sg2042.h"
24 #define R_PLL_STAT (0xC0 - R_PLL_BEGIN)
25 #define R_PLL_CLKEN_CONTROL (0xC4 - R_PLL_BEGIN)
26 #define R_MPLL_CONTROL (0xE8 - R_PLL_BEGIN)
27 #define R_FPLL_CONTROL (0xF4 - R_PLL_BEGIN)
28 #define R_DPLL0_CONTROL (0xF8 - R_PLL_BEGIN)
29 #define R_DPLL1_CONTROL (0xFC - R_PLL_BEGIN)
32 * struct sg2042_pll_clock - PLL clock
36 * **NOTE**: PLL registers are all in SYS_CTRL!
39 * @offset_ctrl: offset of pll control registers
40 * @shift_status_lock: shift of XXX_LOCK in pll status register
41 * @shift_status_updating: shift of UPDATING_XXX in pll status register
42 * @shift_enable: shift of XXX_CLK_EN in pll enable register
91 return FIELD_PREP(PLLCTRL_FBDIV_MASK, ctrl->fbdiv) | in sg2042_pll_ctrl_encode()
92 FIELD_PREP(PLLCTRL_POSTDIV2_MASK, ctrl->postdiv2) | in sg2042_pll_ctrl_encode()
93 FIELD_PREP(PLLCTRL_POSTDIV1_MASK, ctrl->postdiv1) | in sg2042_pll_ctrl_encode()
94 FIELD_PREP(PLLCTRL_REFDIV_MASK, ctrl->refdiv); in sg2042_pll_ctrl_encode()
100 ctrl->fbdiv = FIELD_GET(PLLCTRL_FBDIV_MASK, reg_value); in sg2042_pll_ctrl_decode()
101 ctrl->refdiv = FIELD_GET(PLLCTRL_REFDIV_MASK, reg_value); in sg2042_pll_ctrl_decode()
102 ctrl->postdiv1 = FIELD_GET(PLLCTRL_POSTDIV1_MASK, reg_value); in sg2042_pll_ctrl_decode()
103 ctrl->postdiv2 = FIELD_GET(PLLCTRL_POSTDIV2_MASK, reg_value); in sg2042_pll_ctrl_decode()
106 static inline void sg2042_pll_enable(struct sg2042_pll_clock *pll, bool en) in sg2042_pll_enable() argument
111 /* wait pll lock */ in sg2042_pll_enable()
112 if (readl_poll_timeout_atomic(pll->base + R_PLL_STAT, in sg2042_pll_enable()
114 ((value >> pll->shift_status_lock) & 0x1), in sg2042_pll_enable()
117 pr_warn("%s not locked\n", pll->hw.init->name); in sg2042_pll_enable()
119 /* wait pll updating */ in sg2042_pll_enable()
120 if (readl_poll_timeout_atomic(pll->base + R_PLL_STAT, in sg2042_pll_enable()
122 !((value >> pll->shift_status_updating) & 0x1), in sg2042_pll_enable()
125 pr_warn("%s still updating\n", pll->hw.init->name); in sg2042_pll_enable()
127 /* enable pll */ in sg2042_pll_enable()
128 value = readl(pll->base + R_PLL_CLKEN_CONTROL); in sg2042_pll_enable()
129 writel(value | (1 << pll->shift_enable), pll->base + R_PLL_CLKEN_CONTROL); in sg2042_pll_enable()
131 /* disable pll */ in sg2042_pll_enable()
132 value = readl(pll->base + R_PLL_CLKEN_CONTROL); in sg2042_pll_enable()
133 writel(value & (~(1 << pll->shift_enable)), pll->base + R_PLL_CLKEN_CONTROL); in sg2042_pll_enable()
138 * sg2042_pll_recalc_rate() - Calculate rate for plls
163 * sg2042_pll_get_postdiv_1_2() - Based on input rate/prate/fbdiv/refdiv,
183 * %0 - OK
184 * %-EINVAL - invalid argument, which means Failed to get the postdivs.
237 return -EINVAL; in sg2042_pll_get_postdiv_1_2()
241 * sg2042_get_pll_ctl_setting() - Based on the given FOUTPISTDIV and the input
249 * %0 - OK
250 * %-EINVAL - invalid argument
264 return -EINVAL; in sg2042_get_pll_ctl_setting()
269 return -EINVAL; in sg2042_get_pll_ctl_setting()
305 if (abs_diff(foutpostdiv, req_rate) < abs_diff(best->freq, req_rate)) { in sg2042_get_pll_ctl_setting()
306 best->freq = foutpostdiv; in sg2042_get_pll_ctl_setting()
307 best->refdiv = refdiv; in sg2042_get_pll_ctl_setting()
308 best->fbdiv = fbdiv; in sg2042_get_pll_ctl_setting()
309 best->postdiv1 = postdiv1; in sg2042_get_pll_ctl_setting()
310 best->postdiv2 = postdiv2; in sg2042_get_pll_ctl_setting()
318 if (best->freq == 0) in sg2042_get_pll_ctl_setting()
319 return -EINVAL; in sg2042_get_pll_ctl_setting()
325 * sg2042_clk_pll_recalc_rate() - recalc_rate callback for pll clks
337 struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw); in sg2042_clk_pll_recalc_rate() local
341 value = readl(pll->base + pll->offset_ctrl); in sg2042_clk_pll_recalc_rate()
344 pr_debug("--> %s: pll_recalc_rate: val = %ld\n", in sg2042_clk_pll_recalc_rate()
361 goto out; in sg2042_clk_pll_round_rate()
367 out: in sg2042_clk_pll_round_rate()
368 pr_debug("--> %s: pll_round_rate: val = %ld\n", in sg2042_clk_pll_round_rate()
376 req->rate = sg2042_clk_pll_round_rate(hw, min(req->rate, req->max_rate), in sg2042_clk_pll_determine_rate()
377 &req->best_parent_rate); in sg2042_clk_pll_determine_rate()
378 pr_debug("--> %s: pll_determine_rate: val = %ld\n", in sg2042_clk_pll_determine_rate()
379 clk_hw_get_name(hw), req->rate); in sg2042_clk_pll_determine_rate()
387 struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw); in sg2042_clk_pll_set_rate() local
393 spin_lock_irqsave(pll->lock, flags); in sg2042_clk_pll_set_rate()
395 sg2042_pll_enable(pll, 0); in sg2042_clk_pll_set_rate()
399 pr_warn("%s: Can't find a proper pll setting\n", pll->hw.init->name); in sg2042_clk_pll_set_rate()
400 goto out; in sg2042_clk_pll_set_rate()
406 writel(value, pll->base + pll->offset_ctrl); in sg2042_clk_pll_set_rate()
408 out: in sg2042_clk_pll_set_rate()
409 sg2042_pll_enable(pll, 1); in sg2042_clk_pll_set_rate()
411 spin_unlock_irqrestore(pll->lock, flags); in sg2042_clk_pll_set_rate()
413 pr_debug("--> %s: pll_set_rate: val = 0x%x\n", in sg2042_clk_pll_set_rate()
433 * RO: means Read-Only
477 struct sg2042_pll_clock *pll; in sg2042_clk_register_plls() local
482 pll = &pll_clks[i]; in sg2042_clk_register_plls()
484 pll->base = clk_data->iobase; in sg2042_clk_register_plls()
485 pll->lock = &sg2042_clk_lock; in sg2042_clk_register_plls()
487 hw = &pll->hw; in sg2042_clk_register_plls()
490 pr_err("failed to register clock %s\n", pll->hw.init->name); in sg2042_clk_register_plls()
494 clk_data->onecell_data.hws[pll->id] = hw; in sg2042_clk_register_plls()
506 clk_data = devm_kzalloc(&pdev->dev, in sg2042_init_clkdata()
510 return -ENOMEM; in sg2042_init_clkdata()
512 clk_data->iobase = devm_platform_ioremap_resource(pdev, 0); in sg2042_init_clkdata()
513 if (WARN_ON(IS_ERR(clk_data->iobase))) in sg2042_init_clkdata()
514 return PTR_ERR(clk_data->iobase); in sg2042_init_clkdata()
516 clk_data->onecell_data.num = num_clks; in sg2042_init_clkdata()
535 ret = sg2042_clk_register_plls(&pdev->dev, clk_data, sg2042_pll_clks, in sg2042_pll_probe()
540 return devm_of_clk_add_hw_provider(&pdev->dev, in sg2042_pll_probe()
542 &clk_data->onecell_data); in sg2042_pll_probe()
550 { .compatible = "sophgo,sg2042-pll" },
558 .name = "clk-sophgo-sg2042-pll",
566 MODULE_DESCRIPTION("Sophgo SG2042 pll clock driver");