Lines Matching +full:sg2042 +full:- +full:clkgen

1 // SPDX-License-Identifier: GPL-2.0
3 * Sophgo SG2042 Clock Generator Driver
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
82 * @div_flags: private flags for this clock, not for framework-specific
85 * the initial value pre-configured by IC. BIT[3] controls
91 * and should be sync-ed with the initial value. So in
116 * struct sg2042_gate_clock - Gate clock
132 * struct sg2042_mux_clock - Mux clock
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()
188 if (divider->div_flags & CLK_DIVIDER_READ_ONLY) { in sg2042_clk_divider_round_rate()
189 if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) { in sg2042_clk_divider_round_rate()
190 bestdiv = divider->initval; in sg2042_clk_divider_round_rate()
192 bestdiv = readl(divider->reg) >> divider->shift; in sg2042_clk_divider_round_rate()
193 bestdiv &= clk_div_mask(divider->width); in sg2042_clk_divider_round_rate()
198 divider->width, divider->div_flags); in sg2042_clk_divider_round_rate()
201 pr_debug("--> %s: divider_round_rate: val = %ld\n", in sg2042_clk_divider_round_rate()
215 divider->width, divider->div_flags); in sg2042_clk_divider_set_rate()
217 if (divider->lock) in sg2042_clk_divider_set_rate()
218 spin_lock_irqsave(divider->lock, flags); in sg2042_clk_divider_set_rate()
220 __acquire(divider->lock); in sg2042_clk_divider_set_rate()
226 * De-assert to restore divided clock with new frequency. in sg2042_clk_divider_set_rate()
228 val = readl(divider->reg); in sg2042_clk_divider_set_rate()
232 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
234 if (divider->div_flags & CLK_DIVIDER_HIWORD_MASK) { in sg2042_clk_divider_set_rate()
235 val = clk_div_mask(divider->width) << (divider->shift + 16); in sg2042_clk_divider_set_rate()
237 val = readl(divider->reg); in sg2042_clk_divider_set_rate()
238 val &= ~(clk_div_mask(divider->width) << divider->shift); in sg2042_clk_divider_set_rate()
240 val |= value << divider->shift; in sg2042_clk_divider_set_rate()
242 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
245 /* de-assert */ in sg2042_clk_divider_set_rate()
247 writel(val, divider->reg); in sg2042_clk_divider_set_rate()
249 if (divider->lock) in sg2042_clk_divider_set_rate()
250 spin_unlock_irqrestore(divider->lock, flags); in sg2042_clk_divider_set_rate()
252 __release(divider->lock); in sg2042_clk_divider_set_rate()
254 pr_debug("--> %s: divider_set_rate: register val = 0x%x\n", in sg2042_clk_divider_set_rate()
275 * RO: means Read-Only
422 * Clock items in the array are sorted according to the clock-tree diagram,
727 /* gate clocks downstream from div clocks one-to-one */
823 if (div->div_flags & CLK_DIVIDER_HIWORD_MASK) { in sg2042_clk_register_divs()
824 if (div->width + div->shift > 16) { in sg2042_clk_register_divs()
826 ret = -EINVAL; in sg2042_clk_register_divs()
831 div->reg = clk_data->iobase + div->offset_ctrl; in sg2042_clk_register_divs()
832 div->lock = &sg2042_clk_lock; in sg2042_clk_register_divs()
834 hw = &div->hw; in sg2042_clk_register_divs()
837 pr_err("failed to register clock %s\n", div->hw.init->name); in sg2042_clk_register_divs()
841 clk_data->onecell_data.hws[div->id] = hw; in sg2042_clk_register_divs()
861 gate->hw.init->name, in sg2042_clk_register_gates()
863 gate->hw.init->parent_hws[0], in sg2042_clk_register_gates()
865 gate->hw.init->flags, in sg2042_clk_register_gates()
866 clk_data->iobase + gate->offset_enable, in sg2042_clk_register_gates()
867 gate->bit_idx, in sg2042_clk_register_gates()
871 pr_err("failed to register clock %s\n", gate->hw.init->name); in sg2042_clk_register_gates()
876 clk_data->onecell_data.hws[gate->id] = hw; in sg2042_clk_register_gates()
879 switch (gate->id) { in sg2042_clk_register_gates()
905 gate->hw.init->name, in sg2042_clk_register_gates_fw()
906 gate->hw.init->parent_data, in sg2042_clk_register_gates_fw()
907 gate->hw.init->flags, in sg2042_clk_register_gates_fw()
908 clk_data->iobase + gate->offset_enable, in sg2042_clk_register_gates_fw()
909 gate->bit_idx, in sg2042_clk_register_gates_fw()
913 pr_err("failed to register clock %s\n", gate->hw.init->name); in sg2042_clk_register_gates_fw()
918 clk_data->onecell_data.hws[gate->id] = hw; in sg2042_clk_register_gates_fw()
921 switch (gate->id) { in sg2042_clk_register_gates_fw()
962 hw = __clk_get_hw(ndata->clk); in sg2042_mux_notifier_cb()
966 mux->original_index = ops->get_parent(hw); in sg2042_mux_notifier_cb()
970 * mux. For SG2042, it's fpll for all mux clocks. in sg2042_mux_notifier_cb()
972 * mux, For SG2042, it's mpll. in sg2042_mux_notifier_cb()
975 if (mux->original_index == 0) in sg2042_mux_notifier_cb()
976 ret = ops->set_parent(hw, 1); in sg2042_mux_notifier_cb()
978 ret = ops->set_parent(hw, mux->original_index); in sg2042_mux_notifier_cb()
999 mux->hw.init->name, in sg2042_clk_register_muxs()
1000 mux->hw.init->num_parents, in sg2042_clk_register_muxs()
1002 mux->hw.init->parent_hws, in sg2042_clk_register_muxs()
1004 mux->hw.init->flags, in sg2042_clk_register_muxs()
1005 clk_data->iobase + mux->offset_select, in sg2042_clk_register_muxs()
1006 mux->shift, in sg2042_clk_register_muxs()
1007 BIT(mux->width) - 1, in sg2042_clk_register_muxs()
1012 pr_err("failed to register clock %s\n", mux->hw.init->name); in sg2042_clk_register_muxs()
1017 clk_data->onecell_data.hws[mux->id] = hw; in sg2042_clk_register_muxs()
1020 switch (mux->id) { in sg2042_clk_register_muxs()
1041 if (!(mux->hw.init->flags & CLK_MUX_READ_ONLY)) { in sg2042_clk_register_muxs()
1042 mux->clk_nb.notifier_call = sg2042_mux_notifier_cb; in sg2042_clk_register_muxs()
1043 ret = devm_clk_notifier_register(dev, hw->clk, &mux->clk_nb); in sg2042_clk_register_muxs()
1046 mux->hw.init->name); in sg2042_clk_register_muxs()
1061 clk_data = devm_kzalloc(&pdev->dev, in sg2042_init_clkdata()
1065 return -ENOMEM; in sg2042_init_clkdata()
1067 clk_data->iobase = devm_platform_ioremap_resource(pdev, 0); in sg2042_init_clkdata()
1068 if (WARN_ON(IS_ERR(clk_data->iobase))) in sg2042_init_clkdata()
1069 return PTR_ERR(clk_data->iobase); in sg2042_init_clkdata()
1071 clk_data->onecell_data.num = num_clks; in sg2042_init_clkdata()
1094 /* level-1 gates */ in sg2042_clkgen_probe()
1095 ret = sg2042_clk_register_gates_fw(&pdev->dev, clk_data, in sg2042_clkgen_probe()
1101 /* level-1 div */ in sg2042_clkgen_probe()
1102 ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_1, in sg2042_clkgen_probe()
1108 ret = sg2042_clk_register_muxs(&pdev->dev, clk_data, sg2042_mux_clks, in sg2042_clkgen_probe()
1114 ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_2, in sg2042_clkgen_probe()
1120 ret = sg2042_clk_register_gates(&pdev->dev, clk_data, sg2042_gate_clks_level_2, in sg2042_clkgen_probe()
1125 return devm_of_clk_add_hw_provider(&pdev->dev, in sg2042_clkgen_probe()
1127 &clk_data->onecell_data); in sg2042_clkgen_probe()
1135 { .compatible = "sophgo,sg2042-clkgen" },
1143 .name = "clk-sophgo-sg2042-clkgen",
1151 MODULE_DESCRIPTION("Sophgo SG2042 clock generator driver");