1*ff524079SInochi Amaoto // SPDX-License-Identifier: GPL-2.0
2*ff524079SInochi Amaoto /*
3*ff524079SInochi Amaoto * Sophgo SG2044 PLL clock controller driver
4*ff524079SInochi Amaoto *
5*ff524079SInochi Amaoto * Copyright (C) 2025 Inochi Amaoto <inochiama@gmail.com>
6*ff524079SInochi Amaoto */
7*ff524079SInochi Amaoto
8*ff524079SInochi Amaoto #include <linux/array_size.h>
9*ff524079SInochi Amaoto #include <linux/bitfield.h>
10*ff524079SInochi Amaoto #include <linux/bits.h>
11*ff524079SInochi Amaoto #include <linux/cleanup.h>
12*ff524079SInochi Amaoto #include <linux/clk.h>
13*ff524079SInochi Amaoto #include <linux/clk-provider.h>
14*ff524079SInochi Amaoto #include <linux/io.h>
15*ff524079SInochi Amaoto #include <linux/iopoll.h>
16*ff524079SInochi Amaoto #include <linux/math64.h>
17*ff524079SInochi Amaoto #include <linux/mfd/syscon.h>
18*ff524079SInochi Amaoto #include <linux/platform_device.h>
19*ff524079SInochi Amaoto #include <linux/regmap.h>
20*ff524079SInochi Amaoto #include <linux/spinlock.h>
21*ff524079SInochi Amaoto
22*ff524079SInochi Amaoto #include <dt-bindings/clock/sophgo,sg2044-pll.h>
23*ff524079SInochi Amaoto
24*ff524079SInochi Amaoto /* Low Control part */
25*ff524079SInochi Amaoto #define PLL_VCOSEL_MASK GENMASK(17, 16)
26*ff524079SInochi Amaoto
27*ff524079SInochi Amaoto /* High Control part */
28*ff524079SInochi Amaoto #define PLL_FBDIV_MASK GENMASK(11, 0)
29*ff524079SInochi Amaoto #define PLL_REFDIV_MASK GENMASK(17, 12)
30*ff524079SInochi Amaoto #define PLL_POSTDIV1_MASK GENMASK(20, 18)
31*ff524079SInochi Amaoto #define PLL_POSTDIV2_MASK GENMASK(23, 21)
32*ff524079SInochi Amaoto
33*ff524079SInochi Amaoto #define PLL_CALIBRATE_EN BIT(24)
34*ff524079SInochi Amaoto #define PLL_CALIBRATE_MASK GENMASK(29, 27)
35*ff524079SInochi Amaoto #define PLL_CALIBRATE_DEFAULT FIELD_PREP(PLL_CALIBRATE_MASK, 2)
36*ff524079SInochi Amaoto #define PLL_UPDATE_EN BIT(30)
37*ff524079SInochi Amaoto
38*ff524079SInochi Amaoto #define PLL_HIGH_CTRL_MASK \
39*ff524079SInochi Amaoto (PLL_FBDIV_MASK | PLL_REFDIV_MASK | \
40*ff524079SInochi Amaoto PLL_POSTDIV1_MASK | PLL_POSTDIV2_MASK | \
41*ff524079SInochi Amaoto PLL_CALIBRATE_EN | PLL_CALIBRATE_MASK | \
42*ff524079SInochi Amaoto PLL_UPDATE_EN)
43*ff524079SInochi Amaoto
44*ff524079SInochi Amaoto #define PLL_HIGH_CTRL_OFFSET 4
45*ff524079SInochi Amaoto
46*ff524079SInochi Amaoto #define PLL_VCOSEL_1G6 0x2
47*ff524079SInochi Amaoto #define PLL_VCOSEL_2G4 0x3
48*ff524079SInochi Amaoto
49*ff524079SInochi Amaoto #define PLL_LIMIT_FOUTVCO 0
50*ff524079SInochi Amaoto #define PLL_LIMIT_FOUT 1
51*ff524079SInochi Amaoto #define PLL_LIMIT_REFDIV 2
52*ff524079SInochi Amaoto #define PLL_LIMIT_FBDIV 3
53*ff524079SInochi Amaoto #define PLL_LIMIT_POSTDIV1 4
54*ff524079SInochi Amaoto #define PLL_LIMIT_POSTDIV2 5
55*ff524079SInochi Amaoto
56*ff524079SInochi Amaoto #define for_each_pll_limit_range(_var, _limit) \
57*ff524079SInochi Amaoto for (_var = (_limit)->min; _var <= (_limit)->max; _var++)
58*ff524079SInochi Amaoto
59*ff524079SInochi Amaoto struct sg2044_pll_limit {
60*ff524079SInochi Amaoto u64 min;
61*ff524079SInochi Amaoto u64 max;
62*ff524079SInochi Amaoto };
63*ff524079SInochi Amaoto
64*ff524079SInochi Amaoto struct sg2044_pll_internal {
65*ff524079SInochi Amaoto u32 ctrl_offset;
66*ff524079SInochi Amaoto u32 status_offset;
67*ff524079SInochi Amaoto u32 enable_offset;
68*ff524079SInochi Amaoto
69*ff524079SInochi Amaoto u8 status_lock_bit;
70*ff524079SInochi Amaoto u8 status_updating_bit;
71*ff524079SInochi Amaoto u8 enable_bit;
72*ff524079SInochi Amaoto
73*ff524079SInochi Amaoto const struct sg2044_pll_limit *limits;
74*ff524079SInochi Amaoto };
75*ff524079SInochi Amaoto
76*ff524079SInochi Amaoto struct sg2044_clk_common {
77*ff524079SInochi Amaoto struct clk_hw hw;
78*ff524079SInochi Amaoto struct regmap *regmap;
79*ff524079SInochi Amaoto spinlock_t *lock;
80*ff524079SInochi Amaoto unsigned int id;
81*ff524079SInochi Amaoto };
82*ff524079SInochi Amaoto
83*ff524079SInochi Amaoto struct sg2044_pll {
84*ff524079SInochi Amaoto struct sg2044_clk_common common;
85*ff524079SInochi Amaoto struct sg2044_pll_internal pll;
86*ff524079SInochi Amaoto unsigned int syscon_offset;
87*ff524079SInochi Amaoto };
88*ff524079SInochi Amaoto
89*ff524079SInochi Amaoto struct sg2044_pll_desc_data {
90*ff524079SInochi Amaoto struct sg2044_clk_common * const *pll;
91*ff524079SInochi Amaoto u16 num_pll;
92*ff524079SInochi Amaoto };
93*ff524079SInochi Amaoto
94*ff524079SInochi Amaoto #define SG2044_SYSCON_PLL_OFFSET 0x98
95*ff524079SInochi Amaoto
96*ff524079SInochi Amaoto struct sg2044_pll_ctrl {
97*ff524079SInochi Amaoto spinlock_t lock;
98*ff524079SInochi Amaoto struct clk_hw_onecell_data data;
99*ff524079SInochi Amaoto };
100*ff524079SInochi Amaoto
101*ff524079SInochi Amaoto #define hw_to_sg2044_clk_common(_hw) \
102*ff524079SInochi Amaoto container_of((_hw), struct sg2044_clk_common, hw)
103*ff524079SInochi Amaoto
sg2044_clk_fit_limit(u64 value,const struct sg2044_pll_limit * limit)104*ff524079SInochi Amaoto static inline bool sg2044_clk_fit_limit(u64 value,
105*ff524079SInochi Amaoto const struct sg2044_pll_limit *limit)
106*ff524079SInochi Amaoto {
107*ff524079SInochi Amaoto return value >= limit->min && value <= limit->max;
108*ff524079SInochi Amaoto }
109*ff524079SInochi Amaoto
hw_to_sg2044_pll(struct clk_hw * hw)110*ff524079SInochi Amaoto static inline struct sg2044_pll *hw_to_sg2044_pll(struct clk_hw *hw)
111*ff524079SInochi Amaoto {
112*ff524079SInochi Amaoto return container_of(hw_to_sg2044_clk_common(hw),
113*ff524079SInochi Amaoto struct sg2044_pll, common);
114*ff524079SInochi Amaoto }
115*ff524079SInochi Amaoto
sg2044_pll_calc_vco_rate(unsigned long parent_rate,unsigned long refdiv,unsigned long fbdiv)116*ff524079SInochi Amaoto static unsigned long sg2044_pll_calc_vco_rate(unsigned long parent_rate,
117*ff524079SInochi Amaoto unsigned long refdiv,
118*ff524079SInochi Amaoto unsigned long fbdiv)
119*ff524079SInochi Amaoto {
120*ff524079SInochi Amaoto u64 numerator = parent_rate * fbdiv;
121*ff524079SInochi Amaoto
122*ff524079SInochi Amaoto return div64_ul(numerator, refdiv);
123*ff524079SInochi Amaoto }
124*ff524079SInochi Amaoto
sg2044_pll_calc_rate(unsigned long parent_rate,unsigned long refdiv,unsigned long fbdiv,unsigned long postdiv1,unsigned long postdiv2)125*ff524079SInochi Amaoto static unsigned long sg2044_pll_calc_rate(unsigned long parent_rate,
126*ff524079SInochi Amaoto unsigned long refdiv,
127*ff524079SInochi Amaoto unsigned long fbdiv,
128*ff524079SInochi Amaoto unsigned long postdiv1,
129*ff524079SInochi Amaoto unsigned long postdiv2)
130*ff524079SInochi Amaoto {
131*ff524079SInochi Amaoto u64 numerator, denominator;
132*ff524079SInochi Amaoto
133*ff524079SInochi Amaoto numerator = parent_rate * fbdiv;
134*ff524079SInochi Amaoto denominator = refdiv * (postdiv1 + 1) * (postdiv2 + 1);
135*ff524079SInochi Amaoto
136*ff524079SInochi Amaoto return div64_u64(numerator, denominator);
137*ff524079SInochi Amaoto }
138*ff524079SInochi Amaoto
sg2044_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)139*ff524079SInochi Amaoto static unsigned long sg2044_pll_recalc_rate(struct clk_hw *hw,
140*ff524079SInochi Amaoto unsigned long parent_rate)
141*ff524079SInochi Amaoto {
142*ff524079SInochi Amaoto struct sg2044_pll *pll = hw_to_sg2044_pll(hw);
143*ff524079SInochi Amaoto u32 value;
144*ff524079SInochi Amaoto int ret;
145*ff524079SInochi Amaoto
146*ff524079SInochi Amaoto ret = regmap_read(pll->common.regmap,
147*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.ctrl_offset + PLL_HIGH_CTRL_OFFSET,
148*ff524079SInochi Amaoto &value);
149*ff524079SInochi Amaoto if (ret < 0)
150*ff524079SInochi Amaoto return 0;
151*ff524079SInochi Amaoto
152*ff524079SInochi Amaoto return sg2044_pll_calc_rate(parent_rate,
153*ff524079SInochi Amaoto FIELD_GET(PLL_REFDIV_MASK, value),
154*ff524079SInochi Amaoto FIELD_GET(PLL_FBDIV_MASK, value),
155*ff524079SInochi Amaoto FIELD_GET(PLL_POSTDIV1_MASK, value),
156*ff524079SInochi Amaoto FIELD_GET(PLL_POSTDIV2_MASK, value));
157*ff524079SInochi Amaoto }
158*ff524079SInochi Amaoto
pll_is_better_rate(unsigned long target,unsigned long now,unsigned long best)159*ff524079SInochi Amaoto static bool pll_is_better_rate(unsigned long target, unsigned long now,
160*ff524079SInochi Amaoto unsigned long best)
161*ff524079SInochi Amaoto {
162*ff524079SInochi Amaoto return abs_diff(target, now) < abs_diff(target, best);
163*ff524079SInochi Amaoto }
164*ff524079SInochi Amaoto
sg2042_pll_compute_postdiv(const struct sg2044_pll_limit * limits,unsigned long target,unsigned long parent_rate,unsigned int refdiv,unsigned int fbdiv,unsigned int * postdiv1,unsigned int * postdiv2)165*ff524079SInochi Amaoto static int sg2042_pll_compute_postdiv(const struct sg2044_pll_limit *limits,
166*ff524079SInochi Amaoto unsigned long target,
167*ff524079SInochi Amaoto unsigned long parent_rate,
168*ff524079SInochi Amaoto unsigned int refdiv,
169*ff524079SInochi Amaoto unsigned int fbdiv,
170*ff524079SInochi Amaoto unsigned int *postdiv1,
171*ff524079SInochi Amaoto unsigned int *postdiv2)
172*ff524079SInochi Amaoto {
173*ff524079SInochi Amaoto unsigned int div1, div2;
174*ff524079SInochi Amaoto unsigned long tmp, best_rate = 0;
175*ff524079SInochi Amaoto unsigned int best_div1 = 0, best_div2 = 0;
176*ff524079SInochi Amaoto
177*ff524079SInochi Amaoto for_each_pll_limit_range(div2, &limits[PLL_LIMIT_POSTDIV2]) {
178*ff524079SInochi Amaoto for_each_pll_limit_range(div1, &limits[PLL_LIMIT_POSTDIV1]) {
179*ff524079SInochi Amaoto tmp = sg2044_pll_calc_rate(parent_rate,
180*ff524079SInochi Amaoto refdiv, fbdiv,
181*ff524079SInochi Amaoto div1, div2);
182*ff524079SInochi Amaoto
183*ff524079SInochi Amaoto if (tmp > target)
184*ff524079SInochi Amaoto continue;
185*ff524079SInochi Amaoto
186*ff524079SInochi Amaoto if (pll_is_better_rate(target, tmp, best_rate)) {
187*ff524079SInochi Amaoto best_div1 = div1;
188*ff524079SInochi Amaoto best_div2 = div2;
189*ff524079SInochi Amaoto best_rate = tmp;
190*ff524079SInochi Amaoto
191*ff524079SInochi Amaoto if (tmp == target)
192*ff524079SInochi Amaoto goto find;
193*ff524079SInochi Amaoto }
194*ff524079SInochi Amaoto }
195*ff524079SInochi Amaoto }
196*ff524079SInochi Amaoto
197*ff524079SInochi Amaoto find:
198*ff524079SInochi Amaoto if (best_rate) {
199*ff524079SInochi Amaoto *postdiv1 = best_div1;
200*ff524079SInochi Amaoto *postdiv2 = best_div2;
201*ff524079SInochi Amaoto return 0;
202*ff524079SInochi Amaoto }
203*ff524079SInochi Amaoto
204*ff524079SInochi Amaoto return -EINVAL;
205*ff524079SInochi Amaoto }
206*ff524079SInochi Amaoto
sg2044_compute_pll_setting(const struct sg2044_pll_limit * limits,unsigned long req_rate,unsigned long parent_rate,unsigned int * value)207*ff524079SInochi Amaoto static int sg2044_compute_pll_setting(const struct sg2044_pll_limit *limits,
208*ff524079SInochi Amaoto unsigned long req_rate,
209*ff524079SInochi Amaoto unsigned long parent_rate,
210*ff524079SInochi Amaoto unsigned int *value)
211*ff524079SInochi Amaoto {
212*ff524079SInochi Amaoto unsigned int refdiv, fbdiv, postdiv1, postdiv2;
213*ff524079SInochi Amaoto unsigned int best_refdiv, best_fbdiv, best_postdiv1, best_postdiv2;
214*ff524079SInochi Amaoto unsigned long tmp, best_rate = 0;
215*ff524079SInochi Amaoto int ret;
216*ff524079SInochi Amaoto
217*ff524079SInochi Amaoto for_each_pll_limit_range(fbdiv, &limits[PLL_LIMIT_FBDIV]) {
218*ff524079SInochi Amaoto for_each_pll_limit_range(refdiv, &limits[PLL_LIMIT_REFDIV]) {
219*ff524079SInochi Amaoto u64 vco = sg2044_pll_calc_vco_rate(parent_rate,
220*ff524079SInochi Amaoto refdiv, fbdiv);
221*ff524079SInochi Amaoto if (!sg2044_clk_fit_limit(vco, &limits[PLL_LIMIT_FOUTVCO]))
222*ff524079SInochi Amaoto continue;
223*ff524079SInochi Amaoto
224*ff524079SInochi Amaoto ret = sg2042_pll_compute_postdiv(limits,
225*ff524079SInochi Amaoto req_rate, parent_rate,
226*ff524079SInochi Amaoto refdiv, fbdiv,
227*ff524079SInochi Amaoto &postdiv1, &postdiv2);
228*ff524079SInochi Amaoto if (ret)
229*ff524079SInochi Amaoto continue;
230*ff524079SInochi Amaoto
231*ff524079SInochi Amaoto tmp = sg2044_pll_calc_rate(parent_rate,
232*ff524079SInochi Amaoto refdiv, fbdiv,
233*ff524079SInochi Amaoto postdiv1, postdiv2);
234*ff524079SInochi Amaoto
235*ff524079SInochi Amaoto if (pll_is_better_rate(req_rate, tmp, best_rate)) {
236*ff524079SInochi Amaoto best_refdiv = refdiv;
237*ff524079SInochi Amaoto best_fbdiv = fbdiv;
238*ff524079SInochi Amaoto best_postdiv1 = postdiv1;
239*ff524079SInochi Amaoto best_postdiv2 = postdiv2;
240*ff524079SInochi Amaoto best_rate = tmp;
241*ff524079SInochi Amaoto
242*ff524079SInochi Amaoto if (tmp == req_rate)
243*ff524079SInochi Amaoto goto find;
244*ff524079SInochi Amaoto }
245*ff524079SInochi Amaoto }
246*ff524079SInochi Amaoto }
247*ff524079SInochi Amaoto
248*ff524079SInochi Amaoto find:
249*ff524079SInochi Amaoto if (best_rate) {
250*ff524079SInochi Amaoto *value = FIELD_PREP(PLL_REFDIV_MASK, best_refdiv) |
251*ff524079SInochi Amaoto FIELD_PREP(PLL_FBDIV_MASK, best_fbdiv) |
252*ff524079SInochi Amaoto FIELD_PREP(PLL_POSTDIV1_MASK, best_postdiv1) |
253*ff524079SInochi Amaoto FIELD_PREP(PLL_POSTDIV2_MASK, best_postdiv2);
254*ff524079SInochi Amaoto return 0;
255*ff524079SInochi Amaoto }
256*ff524079SInochi Amaoto
257*ff524079SInochi Amaoto return -EINVAL;
258*ff524079SInochi Amaoto }
259*ff524079SInochi Amaoto
sg2044_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)260*ff524079SInochi Amaoto static int sg2044_pll_determine_rate(struct clk_hw *hw,
261*ff524079SInochi Amaoto struct clk_rate_request *req)
262*ff524079SInochi Amaoto {
263*ff524079SInochi Amaoto struct sg2044_pll *pll = hw_to_sg2044_pll(hw);
264*ff524079SInochi Amaoto unsigned int value;
265*ff524079SInochi Amaoto u64 target;
266*ff524079SInochi Amaoto int ret;
267*ff524079SInochi Amaoto
268*ff524079SInochi Amaoto target = clamp(req->rate, pll->pll.limits[PLL_LIMIT_FOUT].min,
269*ff524079SInochi Amaoto pll->pll.limits[PLL_LIMIT_FOUT].max);
270*ff524079SInochi Amaoto
271*ff524079SInochi Amaoto ret = sg2044_compute_pll_setting(pll->pll.limits, target,
272*ff524079SInochi Amaoto req->best_parent_rate, &value);
273*ff524079SInochi Amaoto if (ret < 0)
274*ff524079SInochi Amaoto return ret;
275*ff524079SInochi Amaoto
276*ff524079SInochi Amaoto req->rate = sg2044_pll_calc_rate(req->best_parent_rate,
277*ff524079SInochi Amaoto FIELD_GET(PLL_REFDIV_MASK, value),
278*ff524079SInochi Amaoto FIELD_GET(PLL_FBDIV_MASK, value),
279*ff524079SInochi Amaoto FIELD_GET(PLL_POSTDIV1_MASK, value),
280*ff524079SInochi Amaoto FIELD_GET(PLL_POSTDIV2_MASK, value));
281*ff524079SInochi Amaoto
282*ff524079SInochi Amaoto return 0;
283*ff524079SInochi Amaoto }
284*ff524079SInochi Amaoto
sg2044_pll_poll_update(struct sg2044_pll * pll)285*ff524079SInochi Amaoto static int sg2044_pll_poll_update(struct sg2044_pll *pll)
286*ff524079SInochi Amaoto {
287*ff524079SInochi Amaoto int ret;
288*ff524079SInochi Amaoto unsigned int value;
289*ff524079SInochi Amaoto
290*ff524079SInochi Amaoto ret = regmap_read_poll_timeout_atomic(pll->common.regmap,
291*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.status_offset,
292*ff524079SInochi Amaoto value,
293*ff524079SInochi Amaoto (value & BIT(pll->pll.status_lock_bit)),
294*ff524079SInochi Amaoto 1, 100000);
295*ff524079SInochi Amaoto if (ret)
296*ff524079SInochi Amaoto return ret;
297*ff524079SInochi Amaoto
298*ff524079SInochi Amaoto return regmap_read_poll_timeout_atomic(pll->common.regmap,
299*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.status_offset,
300*ff524079SInochi Amaoto value,
301*ff524079SInochi Amaoto (!(value & BIT(pll->pll.status_updating_bit))),
302*ff524079SInochi Amaoto 1, 100000);
303*ff524079SInochi Amaoto }
304*ff524079SInochi Amaoto
sg2044_pll_enable(struct sg2044_pll * pll,bool en)305*ff524079SInochi Amaoto static int sg2044_pll_enable(struct sg2044_pll *pll, bool en)
306*ff524079SInochi Amaoto {
307*ff524079SInochi Amaoto if (en) {
308*ff524079SInochi Amaoto if (sg2044_pll_poll_update(pll) < 0)
309*ff524079SInochi Amaoto pr_warn("%s: fail to lock pll\n", clk_hw_get_name(&pll->common.hw));
310*ff524079SInochi Amaoto
311*ff524079SInochi Amaoto return regmap_set_bits(pll->common.regmap,
312*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.enable_offset,
313*ff524079SInochi Amaoto BIT(pll->pll.enable_bit));
314*ff524079SInochi Amaoto }
315*ff524079SInochi Amaoto
316*ff524079SInochi Amaoto return regmap_clear_bits(pll->common.regmap,
317*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.enable_offset,
318*ff524079SInochi Amaoto BIT(pll->pll.enable_bit));
319*ff524079SInochi Amaoto }
320*ff524079SInochi Amaoto
sg2044_pll_update_vcosel(struct sg2044_pll * pll,u64 rate)321*ff524079SInochi Amaoto static int sg2044_pll_update_vcosel(struct sg2044_pll *pll, u64 rate)
322*ff524079SInochi Amaoto {
323*ff524079SInochi Amaoto unsigned int sel;
324*ff524079SInochi Amaoto
325*ff524079SInochi Amaoto if (rate < U64_C(2400000000))
326*ff524079SInochi Amaoto sel = PLL_VCOSEL_1G6;
327*ff524079SInochi Amaoto else
328*ff524079SInochi Amaoto sel = PLL_VCOSEL_2G4;
329*ff524079SInochi Amaoto
330*ff524079SInochi Amaoto return regmap_write_bits(pll->common.regmap,
331*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.ctrl_offset,
332*ff524079SInochi Amaoto PLL_VCOSEL_MASK,
333*ff524079SInochi Amaoto FIELD_PREP(PLL_VCOSEL_MASK, sel));
334*ff524079SInochi Amaoto }
335*ff524079SInochi Amaoto
sg2044_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)336*ff524079SInochi Amaoto static int sg2044_pll_set_rate(struct clk_hw *hw,
337*ff524079SInochi Amaoto unsigned long rate, unsigned long parent_rate)
338*ff524079SInochi Amaoto {
339*ff524079SInochi Amaoto struct sg2044_pll *pll = hw_to_sg2044_pll(hw);
340*ff524079SInochi Amaoto unsigned int value;
341*ff524079SInochi Amaoto u64 vco;
342*ff524079SInochi Amaoto int ret;
343*ff524079SInochi Amaoto
344*ff524079SInochi Amaoto ret = sg2044_compute_pll_setting(pll->pll.limits, rate,
345*ff524079SInochi Amaoto parent_rate, &value);
346*ff524079SInochi Amaoto if (ret < 0)
347*ff524079SInochi Amaoto return ret;
348*ff524079SInochi Amaoto
349*ff524079SInochi Amaoto vco = sg2044_pll_calc_vco_rate(parent_rate,
350*ff524079SInochi Amaoto FIELD_GET(PLL_REFDIV_MASK, value),
351*ff524079SInochi Amaoto FIELD_GET(PLL_FBDIV_MASK, value));
352*ff524079SInochi Amaoto
353*ff524079SInochi Amaoto value |= PLL_CALIBRATE_EN;
354*ff524079SInochi Amaoto value |= PLL_CALIBRATE_DEFAULT;
355*ff524079SInochi Amaoto value |= PLL_UPDATE_EN;
356*ff524079SInochi Amaoto
357*ff524079SInochi Amaoto guard(spinlock_irqsave)(pll->common.lock);
358*ff524079SInochi Amaoto
359*ff524079SInochi Amaoto ret = sg2044_pll_enable(pll, false);
360*ff524079SInochi Amaoto if (ret)
361*ff524079SInochi Amaoto return ret;
362*ff524079SInochi Amaoto
363*ff524079SInochi Amaoto sg2044_pll_update_vcosel(pll, vco);
364*ff524079SInochi Amaoto
365*ff524079SInochi Amaoto regmap_write_bits(pll->common.regmap,
366*ff524079SInochi Amaoto pll->syscon_offset + pll->pll.ctrl_offset +
367*ff524079SInochi Amaoto PLL_HIGH_CTRL_OFFSET,
368*ff524079SInochi Amaoto PLL_HIGH_CTRL_MASK, value);
369*ff524079SInochi Amaoto
370*ff524079SInochi Amaoto sg2044_pll_enable(pll, true);
371*ff524079SInochi Amaoto
372*ff524079SInochi Amaoto return ret;
373*ff524079SInochi Amaoto }
374*ff524079SInochi Amaoto
375*ff524079SInochi Amaoto static const struct clk_ops sg2044_pll_ops = {
376*ff524079SInochi Amaoto .recalc_rate = sg2044_pll_recalc_rate,
377*ff524079SInochi Amaoto .determine_rate = sg2044_pll_determine_rate,
378*ff524079SInochi Amaoto .set_rate = sg2044_pll_set_rate,
379*ff524079SInochi Amaoto };
380*ff524079SInochi Amaoto
381*ff524079SInochi Amaoto static const struct clk_ops sg2044_pll_ro_ops = {
382*ff524079SInochi Amaoto .recalc_rate = sg2044_pll_recalc_rate,
383*ff524079SInochi Amaoto };
384*ff524079SInochi Amaoto
385*ff524079SInochi Amaoto #define SG2044_CLK_COMMON_PDATA(_id, _name, _parents, _op, _flags) \
386*ff524079SInochi Amaoto { \
387*ff524079SInochi Amaoto .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \
388*ff524079SInochi Amaoto _op, (_flags)), \
389*ff524079SInochi Amaoto .id = (_id), \
390*ff524079SInochi Amaoto }
391*ff524079SInochi Amaoto
392*ff524079SInochi Amaoto #define DEFINE_SG2044_PLL(_id, _name, _parent, _flags, \
393*ff524079SInochi Amaoto _ctrl_offset, \
394*ff524079SInochi Amaoto _status_offset, _status_lock_bit, \
395*ff524079SInochi Amaoto _status_updating_bit, \
396*ff524079SInochi Amaoto _enable_offset, _enable_bit, \
397*ff524079SInochi Amaoto _limits) \
398*ff524079SInochi Amaoto struct sg2044_pll _name = { \
399*ff524079SInochi Amaoto .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \
400*ff524079SInochi Amaoto &sg2044_pll_ops, \
401*ff524079SInochi Amaoto (_flags)), \
402*ff524079SInochi Amaoto .pll = { \
403*ff524079SInochi Amaoto .ctrl_offset = (_ctrl_offset), \
404*ff524079SInochi Amaoto .status_offset = (_status_offset), \
405*ff524079SInochi Amaoto .enable_offset = (_enable_offset), \
406*ff524079SInochi Amaoto .status_lock_bit = (_status_lock_bit), \
407*ff524079SInochi Amaoto .status_updating_bit = (_status_updating_bit), \
408*ff524079SInochi Amaoto .enable_bit = (_enable_bit), \
409*ff524079SInochi Amaoto .limits = (_limits), \
410*ff524079SInochi Amaoto }, \
411*ff524079SInochi Amaoto }
412*ff524079SInochi Amaoto
413*ff524079SInochi Amaoto #define DEFINE_SG2044_PLL_RO(_id, _name, _parent, _flags, \
414*ff524079SInochi Amaoto _ctrl_offset, \
415*ff524079SInochi Amaoto _status_offset, _status_lock_bit, \
416*ff524079SInochi Amaoto _status_updating_bit, \
417*ff524079SInochi Amaoto _enable_offset, _enable_bit, \
418*ff524079SInochi Amaoto _limits) \
419*ff524079SInochi Amaoto struct sg2044_pll _name = { \
420*ff524079SInochi Amaoto .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \
421*ff524079SInochi Amaoto &sg2044_pll_ro_ops, \
422*ff524079SInochi Amaoto (_flags)), \
423*ff524079SInochi Amaoto .pll = { \
424*ff524079SInochi Amaoto .ctrl_offset = (_ctrl_offset), \
425*ff524079SInochi Amaoto .status_offset = (_status_offset), \
426*ff524079SInochi Amaoto .enable_offset = (_enable_offset), \
427*ff524079SInochi Amaoto .status_lock_bit = (_status_lock_bit), \
428*ff524079SInochi Amaoto .status_updating_bit = (_status_updating_bit), \
429*ff524079SInochi Amaoto .enable_bit = (_enable_bit), \
430*ff524079SInochi Amaoto .limits = (_limits), \
431*ff524079SInochi Amaoto }, \
432*ff524079SInochi Amaoto }
433*ff524079SInochi Amaoto
434*ff524079SInochi Amaoto static const struct clk_parent_data osc_parents[] = {
435*ff524079SInochi Amaoto { .index = 0 },
436*ff524079SInochi Amaoto };
437*ff524079SInochi Amaoto
438*ff524079SInochi Amaoto static const struct sg2044_pll_limit pll_limits[] = {
439*ff524079SInochi Amaoto [PLL_LIMIT_FOUTVCO] = {
440*ff524079SInochi Amaoto .min = U64_C(1600000000),
441*ff524079SInochi Amaoto .max = U64_C(3200000000),
442*ff524079SInochi Amaoto },
443*ff524079SInochi Amaoto [PLL_LIMIT_FOUT] = {
444*ff524079SInochi Amaoto .min = U64_C(25000),
445*ff524079SInochi Amaoto .max = U64_C(3200000000),
446*ff524079SInochi Amaoto },
447*ff524079SInochi Amaoto [PLL_LIMIT_REFDIV] = {
448*ff524079SInochi Amaoto .min = U64_C(1),
449*ff524079SInochi Amaoto .max = U64_C(63),
450*ff524079SInochi Amaoto },
451*ff524079SInochi Amaoto [PLL_LIMIT_FBDIV] = {
452*ff524079SInochi Amaoto .min = U64_C(8),
453*ff524079SInochi Amaoto .max = U64_C(1066),
454*ff524079SInochi Amaoto },
455*ff524079SInochi Amaoto [PLL_LIMIT_POSTDIV1] = {
456*ff524079SInochi Amaoto .min = U64_C(0),
457*ff524079SInochi Amaoto .max = U64_C(7),
458*ff524079SInochi Amaoto },
459*ff524079SInochi Amaoto [PLL_LIMIT_POSTDIV2] = {
460*ff524079SInochi Amaoto .min = U64_C(0),
461*ff524079SInochi Amaoto .max = U64_C(7),
462*ff524079SInochi Amaoto },
463*ff524079SInochi Amaoto };
464*ff524079SInochi Amaoto
465*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_FPLL0, clk_fpll0, osc_parents, CLK_IS_CRITICAL,
466*ff524079SInochi Amaoto 0x58, 0x00, 22, 6,
467*ff524079SInochi Amaoto 0x04, 6, pll_limits);
468*ff524079SInochi Amaoto
469*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_FPLL1, clk_fpll1, osc_parents, CLK_IS_CRITICAL,
470*ff524079SInochi Amaoto 0x60, 0x00, 23, 7,
471*ff524079SInochi Amaoto 0x04, 7, pll_limits);
472*ff524079SInochi Amaoto
473*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_FPLL2, clk_fpll2, osc_parents, CLK_IS_CRITICAL,
474*ff524079SInochi Amaoto 0x20, 0x08, 16, 0,
475*ff524079SInochi Amaoto 0x0c, 0, pll_limits);
476*ff524079SInochi Amaoto
477*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL0, clk_dpll0, osc_parents, CLK_IS_CRITICAL,
478*ff524079SInochi Amaoto 0x68, 0x00, 24, 8,
479*ff524079SInochi Amaoto 0x04, 8, pll_limits);
480*ff524079SInochi Amaoto
481*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL1, clk_dpll1, osc_parents, CLK_IS_CRITICAL,
482*ff524079SInochi Amaoto 0x70, 0x00, 25, 9,
483*ff524079SInochi Amaoto 0x04, 9, pll_limits);
484*ff524079SInochi Amaoto
485*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL2, clk_dpll2, osc_parents, CLK_IS_CRITICAL,
486*ff524079SInochi Amaoto 0x78, 0x00, 26, 10,
487*ff524079SInochi Amaoto 0x04, 10, pll_limits);
488*ff524079SInochi Amaoto
489*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL3, clk_dpll3, osc_parents, CLK_IS_CRITICAL,
490*ff524079SInochi Amaoto 0x80, 0x00, 27, 11,
491*ff524079SInochi Amaoto 0x04, 11, pll_limits);
492*ff524079SInochi Amaoto
493*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL4, clk_dpll4, osc_parents, CLK_IS_CRITICAL,
494*ff524079SInochi Amaoto 0x88, 0x00, 28, 12,
495*ff524079SInochi Amaoto 0x04, 12, pll_limits);
496*ff524079SInochi Amaoto
497*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL5, clk_dpll5, osc_parents, CLK_IS_CRITICAL,
498*ff524079SInochi Amaoto 0x90, 0x00, 29, 13,
499*ff524079SInochi Amaoto 0x04, 13, pll_limits);
500*ff524079SInochi Amaoto
501*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL6, clk_dpll6, osc_parents, CLK_IS_CRITICAL,
502*ff524079SInochi Amaoto 0x98, 0x00, 30, 14,
503*ff524079SInochi Amaoto 0x04, 14, pll_limits);
504*ff524079SInochi Amaoto
505*ff524079SInochi Amaoto static DEFINE_SG2044_PLL_RO(CLK_DPLL7, clk_dpll7, osc_parents, CLK_IS_CRITICAL,
506*ff524079SInochi Amaoto 0xa0, 0x00, 31, 15,
507*ff524079SInochi Amaoto 0x04, 15, pll_limits);
508*ff524079SInochi Amaoto
509*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL0, clk_mpll0, osc_parents, CLK_IS_CRITICAL,
510*ff524079SInochi Amaoto 0x28, 0x00, 16, 0,
511*ff524079SInochi Amaoto 0x04, 0, pll_limits);
512*ff524079SInochi Amaoto
513*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL1, clk_mpll1, osc_parents, CLK_IS_CRITICAL,
514*ff524079SInochi Amaoto 0x30, 0x00, 17, 1,
515*ff524079SInochi Amaoto 0x04, 1, pll_limits);
516*ff524079SInochi Amaoto
517*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL2, clk_mpll2, osc_parents, CLK_IS_CRITICAL,
518*ff524079SInochi Amaoto 0x38, 0x00, 18, 2,
519*ff524079SInochi Amaoto 0x04, 2, pll_limits);
520*ff524079SInochi Amaoto
521*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL3, clk_mpll3, osc_parents, CLK_IS_CRITICAL,
522*ff524079SInochi Amaoto 0x40, 0x00, 19, 3,
523*ff524079SInochi Amaoto 0x04, 3, pll_limits);
524*ff524079SInochi Amaoto
525*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL4, clk_mpll4, osc_parents, CLK_IS_CRITICAL,
526*ff524079SInochi Amaoto 0x48, 0x00, 20, 4,
527*ff524079SInochi Amaoto 0x04, 4, pll_limits);
528*ff524079SInochi Amaoto
529*ff524079SInochi Amaoto static DEFINE_SG2044_PLL(CLK_MPLL5, clk_mpll5, osc_parents, CLK_IS_CRITICAL,
530*ff524079SInochi Amaoto 0x50, 0x00, 21, 5,
531*ff524079SInochi Amaoto 0x04, 5, pll_limits);
532*ff524079SInochi Amaoto
533*ff524079SInochi Amaoto static struct sg2044_clk_common * const sg2044_pll_commons[] = {
534*ff524079SInochi Amaoto &clk_fpll0.common,
535*ff524079SInochi Amaoto &clk_fpll1.common,
536*ff524079SInochi Amaoto &clk_fpll2.common,
537*ff524079SInochi Amaoto &clk_dpll0.common,
538*ff524079SInochi Amaoto &clk_dpll1.common,
539*ff524079SInochi Amaoto &clk_dpll2.common,
540*ff524079SInochi Amaoto &clk_dpll3.common,
541*ff524079SInochi Amaoto &clk_dpll4.common,
542*ff524079SInochi Amaoto &clk_dpll5.common,
543*ff524079SInochi Amaoto &clk_dpll6.common,
544*ff524079SInochi Amaoto &clk_dpll7.common,
545*ff524079SInochi Amaoto &clk_mpll0.common,
546*ff524079SInochi Amaoto &clk_mpll1.common,
547*ff524079SInochi Amaoto &clk_mpll2.common,
548*ff524079SInochi Amaoto &clk_mpll3.common,
549*ff524079SInochi Amaoto &clk_mpll4.common,
550*ff524079SInochi Amaoto &clk_mpll5.common,
551*ff524079SInochi Amaoto };
552*ff524079SInochi Amaoto
sg2044_pll_init_ctrl(struct device * dev,struct regmap * regmap,struct sg2044_pll_ctrl * ctrl,const struct sg2044_pll_desc_data * desc)553*ff524079SInochi Amaoto static int sg2044_pll_init_ctrl(struct device *dev, struct regmap *regmap,
554*ff524079SInochi Amaoto struct sg2044_pll_ctrl *ctrl,
555*ff524079SInochi Amaoto const struct sg2044_pll_desc_data *desc)
556*ff524079SInochi Amaoto {
557*ff524079SInochi Amaoto int ret, i;
558*ff524079SInochi Amaoto
559*ff524079SInochi Amaoto spin_lock_init(&ctrl->lock);
560*ff524079SInochi Amaoto
561*ff524079SInochi Amaoto for (i = 0; i < desc->num_pll; i++) {
562*ff524079SInochi Amaoto struct sg2044_clk_common *common = desc->pll[i];
563*ff524079SInochi Amaoto struct sg2044_pll *pll = hw_to_sg2044_pll(&common->hw);
564*ff524079SInochi Amaoto
565*ff524079SInochi Amaoto common->lock = &ctrl->lock;
566*ff524079SInochi Amaoto common->regmap = regmap;
567*ff524079SInochi Amaoto pll->syscon_offset = SG2044_SYSCON_PLL_OFFSET;
568*ff524079SInochi Amaoto
569*ff524079SInochi Amaoto ret = devm_clk_hw_register(dev, &common->hw);
570*ff524079SInochi Amaoto if (ret)
571*ff524079SInochi Amaoto return ret;
572*ff524079SInochi Amaoto
573*ff524079SInochi Amaoto ctrl->data.hws[common->id] = &common->hw;
574*ff524079SInochi Amaoto }
575*ff524079SInochi Amaoto
576*ff524079SInochi Amaoto return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
577*ff524079SInochi Amaoto &ctrl->data);
578*ff524079SInochi Amaoto }
579*ff524079SInochi Amaoto
sg2044_pll_probe(struct platform_device * pdev)580*ff524079SInochi Amaoto static int sg2044_pll_probe(struct platform_device *pdev)
581*ff524079SInochi Amaoto {
582*ff524079SInochi Amaoto struct device *dev = &pdev->dev;
583*ff524079SInochi Amaoto struct sg2044_pll_ctrl *ctrl;
584*ff524079SInochi Amaoto const struct sg2044_pll_desc_data *desc;
585*ff524079SInochi Amaoto struct regmap *regmap;
586*ff524079SInochi Amaoto
587*ff524079SInochi Amaoto regmap = device_node_to_regmap(pdev->dev.parent->of_node);
588*ff524079SInochi Amaoto if (IS_ERR(regmap))
589*ff524079SInochi Amaoto return dev_err_probe(dev, PTR_ERR(regmap),
590*ff524079SInochi Amaoto "fail to get the regmap for PLL\n");
591*ff524079SInochi Amaoto
592*ff524079SInochi Amaoto desc = (const struct sg2044_pll_desc_data *)platform_get_device_id(pdev)->driver_data;
593*ff524079SInochi Amaoto if (!desc)
594*ff524079SInochi Amaoto return dev_err_probe(dev, -EINVAL, "no match data for platform\n");
595*ff524079SInochi Amaoto
596*ff524079SInochi Amaoto ctrl = devm_kzalloc(dev, struct_size(ctrl, data.hws, desc->num_pll), GFP_KERNEL);
597*ff524079SInochi Amaoto if (!ctrl)
598*ff524079SInochi Amaoto return -ENOMEM;
599*ff524079SInochi Amaoto
600*ff524079SInochi Amaoto ctrl->data.num = desc->num_pll;
601*ff524079SInochi Amaoto
602*ff524079SInochi Amaoto return sg2044_pll_init_ctrl(dev, regmap, ctrl, desc);
603*ff524079SInochi Amaoto }
604*ff524079SInochi Amaoto
605*ff524079SInochi Amaoto static const struct sg2044_pll_desc_data sg2044_pll_desc_data = {
606*ff524079SInochi Amaoto .pll = sg2044_pll_commons,
607*ff524079SInochi Amaoto .num_pll = ARRAY_SIZE(sg2044_pll_commons),
608*ff524079SInochi Amaoto };
609*ff524079SInochi Amaoto
610*ff524079SInochi Amaoto static const struct platform_device_id sg2044_pll_match[] = {
611*ff524079SInochi Amaoto { .name = "sg2044-pll",
612*ff524079SInochi Amaoto .driver_data = (unsigned long)&sg2044_pll_desc_data },
613*ff524079SInochi Amaoto { /* sentinel */ }
614*ff524079SInochi Amaoto };
615*ff524079SInochi Amaoto MODULE_DEVICE_TABLE(platform, sg2044_pll_match);
616*ff524079SInochi Amaoto
617*ff524079SInochi Amaoto static struct platform_driver sg2044_clk_driver = {
618*ff524079SInochi Amaoto .probe = sg2044_pll_probe,
619*ff524079SInochi Amaoto .driver = {
620*ff524079SInochi Amaoto .name = "sg2044-pll",
621*ff524079SInochi Amaoto },
622*ff524079SInochi Amaoto .id_table = sg2044_pll_match,
623*ff524079SInochi Amaoto };
624*ff524079SInochi Amaoto module_platform_driver(sg2044_clk_driver);
625*ff524079SInochi Amaoto
626*ff524079SInochi Amaoto MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>");
627*ff524079SInochi Amaoto MODULE_DESCRIPTION("Sophgo SG2044 pll clock driver");
628*ff524079SInochi Amaoto MODULE_LICENSE("GPL");
629