1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
6 #include <linux/slab.h>
7 #include <linux/clk-provider.h>
10 #define div_mask(width) ((1 << (width)) - 1)
12 static bool _is_best_half_div(unsigned long rate
, unsigned long now
,
13 unsigned long best
, unsigned long flags
)
15 if (flags
& CLK_DIVIDER_ROUND_CLOSEST
)
16 return abs(rate
- now
) < abs(rate
- best
);
18 return now
<= rate
&& now
> best
;
21 static unsigned long clk_half_divider_recalc_rate(struct clk_hw
*hw
,
22 unsigned long parent_rate
)
24 struct clk_divider
*divider
= to_clk_divider(hw
);
27 val
= clk_readl(divider
->reg
) >> divider
->shift
;
28 val
&= div_mask(divider
->width
);
31 return DIV_ROUND_UP_ULL(((u64
)parent_rate
* 2), val
);
34 static int clk_half_divider_bestdiv(struct clk_hw
*hw
, unsigned long rate
,
35 unsigned long *best_parent_rate
, u8 width
,
38 unsigned int i
, bestdiv
= 0;
39 unsigned long parent_rate
, best
= 0, now
, maxdiv
;
40 unsigned long parent_rate_saved
= *best_parent_rate
;
45 maxdiv
= div_mask(width
);
47 if (!(clk_hw_get_flags(hw
) & CLK_SET_RATE_PARENT
)) {
48 parent_rate
= *best_parent_rate
;
49 bestdiv
= DIV_ROUND_UP_ULL(((u64
)parent_rate
* 2), rate
);
53 bestdiv
= (bestdiv
- 3) / 2;
54 bestdiv
= bestdiv
> maxdiv
? maxdiv
: bestdiv
;
59 * The maximum divider we can use without overflowing
60 * unsigned long in rate * i below
62 maxdiv
= min(ULONG_MAX
/ rate
, maxdiv
);
64 for (i
= 0; i
<= maxdiv
; i
++) {
65 if (((u64
)rate
* (i
* 2 + 3)) == ((u64
)parent_rate_saved
* 2)) {
67 * It's the most ideal case if the requested rate can be
68 * divided from parent clock without needing to change
69 * parent rate, so return the divider immediately.
71 *best_parent_rate
= parent_rate_saved
;
74 parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
),
75 ((u64
)rate
* (i
* 2 + 3)) / 2);
76 now
= DIV_ROUND_UP_ULL(((u64
)parent_rate
* 2),
79 if (_is_best_half_div(rate
, now
, best
, flags
)) {
82 *best_parent_rate
= parent_rate
;
87 bestdiv
= div_mask(width
);
88 *best_parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
), 1);
94 static long clk_half_divider_round_rate(struct clk_hw
*hw
, unsigned long rate
,
97 struct clk_divider
*divider
= to_clk_divider(hw
);
100 div
= clk_half_divider_bestdiv(hw
, rate
, prate
,
104 return DIV_ROUND_UP_ULL(((u64
)*prate
* 2), div
* 2 + 3);
107 static int clk_half_divider_set_rate(struct clk_hw
*hw
, unsigned long rate
,
108 unsigned long parent_rate
)
110 struct clk_divider
*divider
= to_clk_divider(hw
);
112 unsigned long flags
= 0;
115 value
= DIV_ROUND_UP_ULL(((u64
)parent_rate
* 2), rate
);
116 value
= (value
- 3) / 2;
117 value
= min_t(unsigned int, value
, div_mask(divider
->width
));
120 spin_lock_irqsave(divider
->lock
, flags
);
122 __acquire(divider
->lock
);
124 if (divider
->flags
& CLK_DIVIDER_HIWORD_MASK
) {
125 val
= div_mask(divider
->width
) << (divider
->shift
+ 16);
127 val
= clk_readl(divider
->reg
);
128 val
&= ~(div_mask(divider
->width
) << divider
->shift
);
130 val
|= value
<< divider
->shift
;
131 clk_writel(val
, divider
->reg
);
134 spin_unlock_irqrestore(divider
->lock
, flags
);
136 __release(divider
->lock
);
141 const struct clk_ops clk_half_divider_ops
= {
142 .recalc_rate
= clk_half_divider_recalc_rate
,
143 .round_rate
= clk_half_divider_round_rate
,
144 .set_rate
= clk_half_divider_set_rate
,
146 EXPORT_SYMBOL_GPL(clk_half_divider_ops
);
149 * Register a clock branch.
150 * Most clock branches have a form like
153 * |M |--[GATE]-[DIV]-
156 * sometimes without one of those components.
158 struct clk
*rockchip_clk_register_halfdiv(const char *name
,
159 const char *const *parent_names
,
160 u8 num_parents
, void __iomem
*base
,
161 int muxdiv_offset
, u8 mux_shift
,
162 u8 mux_width
, u8 mux_flags
,
163 u8 div_shift
, u8 div_width
,
164 u8 div_flags
, int gate_offset
,
165 u8 gate_shift
, u8 gate_flags
,
170 struct clk_mux
*mux
= NULL
;
171 struct clk_gate
*gate
= NULL
;
172 struct clk_divider
*div
= NULL
;
173 const struct clk_ops
*mux_ops
= NULL
, *div_ops
= NULL
,
176 if (num_parents
> 1) {
177 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
179 return ERR_PTR(-ENOMEM
);
181 mux
->reg
= base
+ muxdiv_offset
;
182 mux
->shift
= mux_shift
;
183 mux
->mask
= BIT(mux_width
) - 1;
184 mux
->flags
= mux_flags
;
186 mux_ops
= (mux_flags
& CLK_MUX_READ_ONLY
) ? &clk_mux_ro_ops
190 if (gate_offset
>= 0) {
191 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
195 gate
->flags
= gate_flags
;
196 gate
->reg
= base
+ gate_offset
;
197 gate
->bit_idx
= gate_shift
;
199 gate_ops
= &clk_gate_ops
;
203 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
207 div
->flags
= div_flags
;
208 div
->reg
= base
+ muxdiv_offset
;
209 div
->shift
= div_shift
;
210 div
->width
= div_width
;
212 div_ops
= &clk_half_divider_ops
;
215 clk
= clk_register_composite(NULL
, name
, parent_names
, num_parents
,
216 mux
? &mux
->hw
: NULL
, mux_ops
,
217 div
? &div
->hw
: NULL
, div_ops
,
218 gate
? &gate
->hw
: NULL
, gate_ops
,
226 return ERR_PTR(-ENOMEM
);