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