Lines Matching +full:divider +full:- +full:width

1 // SPDX-License-Identifier: GPL-2.0
12 #include <linux/clk-provider.h>
17 #include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
19 #include "clk-sg2042.h"
23 #define R_PLL_STAT (0xC0 - R_PLL_BEGIN)
24 #define R_PLL_CLKEN_CONTROL (0xC4 - R_PLL_BEGIN)
25 #define R_MPLL_CONTROL (0xE8 - R_PLL_BEGIN)
26 #define R_FPLL_CONTROL (0xF4 - R_PLL_BEGIN)
27 #define R_DPLL0_CONTROL (0xF8 - R_PLL_BEGIN)
28 #define R_DPLL1_CONTROL (0xFC - R_PLL_BEGIN)
72 * struct sg2042_divider_clock - Divider clock
79 * @offset_ctrl: offset of divider control registers
80 * @shift: shift of "Clock Divider Factor" in divider control register
81 * @width: width of "Clock Divider Factor" in divider control register
82 * @div_flags: private flags for this clock, not for framework-specific
83 * @initval: In the divider control register, we can configure whether
84 * to use the value of "Clock Divider Factor" or just use
85 * the initial value pre-configured by IC. BIT[3] controls
89 * value when poweron) and default value of "Clock Divider
91 * and should be sync-ed with the initial value. So in
107 u8 width; member
116 * struct sg2042_gate_clock - Gate clock
132 * struct sg2042_mux_clock - Mux clock
138 * @width: width of "Clock Select" in mux selection register
149 u8 width; member
160 struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); in sg2042_clk_divider_recalc_rate() local
164 if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) { in sg2042_clk_divider_recalc_rate()
165 val = divider->initval; in sg2042_clk_divider_recalc_rate()
167 val = readl(divider->reg) >> divider->shift; in sg2042_clk_divider_recalc_rate()
168 val &= clk_div_mask(divider->width); in sg2042_clk_divider_recalc_rate()
172 divider->div_flags, divider->width); in sg2042_clk_divider_recalc_rate()
174 pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n", in sg2042_clk_divider_recalc_rate()
182 struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); in sg2042_clk_divider_determine_rate() local
187 if (divider->div_flags & CLK_DIVIDER_READ_ONLY) { in sg2042_clk_divider_determine_rate()
188 if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) { in sg2042_clk_divider_determine_rate()
189 bestdiv = divider->initval; in sg2042_clk_divider_determine_rate()
191 bestdiv = readl(divider->reg) >> divider->shift; in sg2042_clk_divider_determine_rate()
192 bestdiv &= clk_div_mask(divider->width); in sg2042_clk_divider_determine_rate()
194 ret_rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); in sg2042_clk_divider_determine_rate()
196 ret_rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, NULL, in sg2042_clk_divider_determine_rate()
197 divider->width, divider->div_flags); in sg2042_clk_divider_determine_rate()
200 pr_debug("--> %s: divider_round_rate: val = %ld\n", in sg2042_clk_divider_determine_rate()
202 req->rate = ret_rate; in sg2042_clk_divider_determine_rate()
211 struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); in sg2042_clk_divider_set_rate() local
216 divider->width, divider->div_flags); in sg2042_clk_divider_set_rate()
218 if (divider->lock) in sg2042_clk_divider_set_rate()
219 spin_lock_irqsave(divider->lock, flags); in sg2042_clk_divider_set_rate()
221 __acquire(divider->lock); in sg2042_clk_divider_set_rate()
225 * Assert to reset divider. in sg2042_clk_divider_set_rate()
227 * De-assert to restore divided clock with new frequency. in sg2042_clk_divider_set_rate()
229 val = readl(divider->reg); in sg2042_clk_divider_set_rate()
233 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
235 if (divider->div_flags & CLK_DIVIDER_HIWORD_MASK) { in sg2042_clk_divider_set_rate()
236 val = clk_div_mask(divider->width) << (divider->shift + 16); in sg2042_clk_divider_set_rate()
238 val = readl(divider->reg); in sg2042_clk_divider_set_rate()
239 val &= ~(clk_div_mask(divider->width) << divider->shift); in sg2042_clk_divider_set_rate()
241 val |= value << divider->shift; in sg2042_clk_divider_set_rate()
243 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
246 /* de-assert */ in sg2042_clk_divider_set_rate()
248 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
250 if (divider->lock) in sg2042_clk_divider_set_rate()
251 spin_unlock_irqrestore(divider->lock, flags); in sg2042_clk_divider_set_rate()
253 __release(divider->lock); in sg2042_clk_divider_set_rate()
255 pr_debug("--> %s: divider_set_rate: register val = 0x%x\n", in sg2042_clk_divider_set_rate()
276 * RO: means Read-Only
289 .width = _width, \
305 .width = _width, \
321 .width = _width, \
337 .width = _width, \
353 .width = _width, \
369 .width = _width, \
419 .width = _width, \
423 * Clock items in the array are sorted according to the clock-tree diagram,
505 * "clk_div_ddr01_0" is the name of Clock divider 0 control of DDR01, and
508 * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
624 * Set clk_div_uart_500m as RO, because the width of CLKDIVREG4 is too
625 * narrow for us to produce 115200. Use UART internal divider directly.
728 /* gate clocks downstream from div clocks one-to-one */
824 if (div->div_flags & CLK_DIVIDER_HIWORD_MASK) { in sg2042_clk_register_divs()
825 if (div->width + div->shift > 16) { in sg2042_clk_register_divs()
826 pr_warn("divider value exceeds LOWORD field\n"); in sg2042_clk_register_divs()
827 ret = -EINVAL; in sg2042_clk_register_divs()
832 div->reg = clk_data->iobase + div->offset_ctrl; in sg2042_clk_register_divs()
833 div->lock = &sg2042_clk_lock; in sg2042_clk_register_divs()
835 hw = &div->hw; in sg2042_clk_register_divs()
838 pr_err("failed to register clock %s\n", div->hw.init->name); in sg2042_clk_register_divs()
842 clk_data->onecell_data.hws[div->id] = hw; in sg2042_clk_register_divs()
862 gate->hw.init->name, in sg2042_clk_register_gates()
864 gate->hw.init->parent_hws[0], in sg2042_clk_register_gates()
866 gate->hw.init->flags, in sg2042_clk_register_gates()
867 clk_data->iobase + gate->offset_enable, in sg2042_clk_register_gates()
868 gate->bit_idx, in sg2042_clk_register_gates()
872 pr_err("failed to register clock %s\n", gate->hw.init->name); in sg2042_clk_register_gates()
877 clk_data->onecell_data.hws[gate->id] = hw; in sg2042_clk_register_gates()
880 switch (gate->id) { in sg2042_clk_register_gates()
906 gate->hw.init->name, in sg2042_clk_register_gates_fw()
907 gate->hw.init->parent_data, in sg2042_clk_register_gates_fw()
908 gate->hw.init->flags, in sg2042_clk_register_gates_fw()
909 clk_data->iobase + gate->offset_enable, in sg2042_clk_register_gates_fw()
910 gate->bit_idx, in sg2042_clk_register_gates_fw()
914 pr_err("failed to register clock %s\n", gate->hw.init->name); in sg2042_clk_register_gates_fw()
919 clk_data->onecell_data.hws[gate->id] = hw; in sg2042_clk_register_gates_fw()
922 switch (gate->id) { in sg2042_clk_register_gates_fw()
963 hw = __clk_get_hw(ndata->clk); in sg2042_mux_notifier_cb()
967 mux->original_index = ops->get_parent(hw); in sg2042_mux_notifier_cb()
976 if (mux->original_index == 0) in sg2042_mux_notifier_cb()
977 ret = ops->set_parent(hw, 1); in sg2042_mux_notifier_cb()
979 ret = ops->set_parent(hw, mux->original_index); in sg2042_mux_notifier_cb()
1000 mux->hw.init->name, in sg2042_clk_register_muxs()
1001 mux->hw.init->num_parents, in sg2042_clk_register_muxs()
1003 mux->hw.init->parent_hws, in sg2042_clk_register_muxs()
1005 mux->hw.init->flags, in sg2042_clk_register_muxs()
1006 clk_data->iobase + mux->offset_select, in sg2042_clk_register_muxs()
1007 mux->shift, in sg2042_clk_register_muxs()
1008 BIT(mux->width) - 1, in sg2042_clk_register_muxs()
1013 pr_err("failed to register clock %s\n", mux->hw.init->name); in sg2042_clk_register_muxs()
1018 clk_data->onecell_data.hws[mux->id] = hw; in sg2042_clk_register_muxs()
1021 switch (mux->id) { in sg2042_clk_register_muxs()
1042 if (!(mux->hw.init->flags & CLK_MUX_READ_ONLY)) { in sg2042_clk_register_muxs()
1043 mux->clk_nb.notifier_call = sg2042_mux_notifier_cb; in sg2042_clk_register_muxs()
1044 ret = devm_clk_notifier_register(dev, hw->clk, &mux->clk_nb); in sg2042_clk_register_muxs()
1047 mux->hw.init->name); in sg2042_clk_register_muxs()
1062 clk_data = devm_kzalloc(&pdev->dev, in sg2042_init_clkdata()
1066 return -ENOMEM; in sg2042_init_clkdata()
1068 clk_data->iobase = devm_platform_ioremap_resource(pdev, 0); in sg2042_init_clkdata()
1069 if (WARN_ON(IS_ERR(clk_data->iobase))) in sg2042_init_clkdata()
1070 return PTR_ERR(clk_data->iobase); in sg2042_init_clkdata()
1072 clk_data->onecell_data.num = num_clks; in sg2042_init_clkdata()
1095 /* level-1 gates */ in sg2042_clkgen_probe()
1096 ret = sg2042_clk_register_gates_fw(&pdev->dev, clk_data, in sg2042_clkgen_probe()
1102 /* level-1 div */ in sg2042_clkgen_probe()
1103 ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_1, in sg2042_clkgen_probe()
1109 ret = sg2042_clk_register_muxs(&pdev->dev, clk_data, sg2042_mux_clks, in sg2042_clkgen_probe()
1115 ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_2, in sg2042_clkgen_probe()
1121 ret = sg2042_clk_register_gates(&pdev->dev, clk_data, sg2042_gate_clks_level_2, in sg2042_clkgen_probe()
1126 return devm_of_clk_add_hw_provider(&pdev->dev, in sg2042_clkgen_probe()
1128 &clk_data->onecell_data); in sg2042_clkgen_probe()
1136 { .compatible = "sophgo,sg2042-clkgen" },
1144 .name = "clk-sophgo-sg2042-clkgen",