Lines Matching +full:clock +full:- +full:div
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015 Chen-Yu Tsai
5 * Chen-Yu Tsai <[email protected]>
7 * Allwinner A80 CPUS clock driver
12 #include <linux/clk-provider.h>
33 #define SUN9I_CPUS_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_DIV_MASK) | \ argument
34 (div << SUN9I_CPUS_DIV_SHIFT))
39 #define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \ argument
40 (div << SUN9I_CPUS_PLL4_DIV_SHIFT))
57 reg = readl(cpus->reg); in sun9i_a80_cpus_clk_recalc_rate()
59 /* apply pre-divider first if parent is pll4 */ in sun9i_a80_cpus_clk_recalc_rate()
72 u8 div, pre_div = 1; in sun9i_a80_cpus_clk_round() local
75 * clock can only divide, so we will never be able to achieve in sun9i_a80_cpus_clk_round()
81 div = DIV_ROUND_UP(parent_rate, rate); in sun9i_a80_cpus_clk_round()
83 /* calculate pre-divider if parent is pll4 */ in sun9i_a80_cpus_clk_round()
84 if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) { in sun9i_a80_cpus_clk_round()
85 /* pre-divider is 1 ~ 32 */ in sun9i_a80_cpus_clk_round()
86 if (div < 32) { in sun9i_a80_cpus_clk_round()
87 pre_div = div; in sun9i_a80_cpus_clk_round()
88 div = 1; in sun9i_a80_cpus_clk_round()
89 } else if (div < 64) { in sun9i_a80_cpus_clk_round()
90 pre_div = DIV_ROUND_UP(div, 2); in sun9i_a80_cpus_clk_round()
91 div = 2; in sun9i_a80_cpus_clk_round()
92 } else if (div < 96) { in sun9i_a80_cpus_clk_round()
93 pre_div = DIV_ROUND_UP(div, 3); in sun9i_a80_cpus_clk_round()
94 div = 3; in sun9i_a80_cpus_clk_round()
96 pre_div = DIV_ROUND_UP(div, 4); in sun9i_a80_cpus_clk_round()
97 div = 4; in sun9i_a80_cpus_clk_round()
103 *divp = div - 1; in sun9i_a80_cpus_clk_round()
104 *pre_divp = pre_div - 1; in sun9i_a80_cpus_clk_round()
107 return parent_rate / pre_div / div; in sun9i_a80_cpus_clk_round()
116 unsigned long rate = req->rate; in sun9i_a80_cpus_clk_determine_rate()
140 return -EINVAL; in sun9i_a80_cpus_clk_determine_rate()
142 req->best_parent_hw = best_parent; in sun9i_a80_cpus_clk_determine_rate()
143 req->best_parent_rate = best; in sun9i_a80_cpus_clk_determine_rate()
144 req->rate = best_child_rate; in sun9i_a80_cpus_clk_determine_rate()
154 u8 div, pre_div, parent; in sun9i_a80_cpus_clk_set_rate() local
159 reg = readl(cpus->reg); in sun9i_a80_cpus_clk_set_rate()
161 /* need to know which parent is used to apply pre-divider */ in sun9i_a80_cpus_clk_set_rate()
163 sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate); in sun9i_a80_cpus_clk_set_rate()
165 reg = SUN9I_CPUS_DIV_SET(reg, div); in sun9i_a80_cpus_clk_set_rate()
167 writel(reg, cpus->reg); in sun9i_a80_cpus_clk_set_rate()
181 * sun9i_a80_cpus_setup() - Setup function for a80 cpus composite clk
182 * @node: &struct device_node for the clock
186 const char *clk_name = node->name; in sun9i_a80_cpus_setup()
198 cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node)); in sun9i_a80_cpus_setup()
199 if (IS_ERR(cpus->reg)) in sun9i_a80_cpus_setup()
202 of_property_read_string(node, "clock-output-names", &clk_name); in sun9i_a80_cpus_setup()
211 /* set up clock properties */ in sun9i_a80_cpus_setup()
212 mux->reg = cpus->reg; in sun9i_a80_cpus_setup()
213 mux->shift = SUN9I_CPUS_MUX_SHIFT; in sun9i_a80_cpus_setup()
214 /* un-shifted mask is what mux_clk expects */ in sun9i_a80_cpus_setup()
215 mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT; in sun9i_a80_cpus_setup()
216 mux->lock = &sun9i_a80_cpus_lock; in sun9i_a80_cpus_setup()
219 &mux->hw, &clk_mux_ops, in sun9i_a80_cpus_setup()
220 &cpus->hw, &sun9i_a80_cpus_clk_ops, in sun9i_a80_cpus_setup()
236 iounmap(cpus->reg); in sun9i_a80_cpus_setup()
242 CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",