1 // SPDX-License-Identifier: GPL-2.0
3 * Sophgo SG2042 Clock Generator Driver
5 * Copyright (C) 2024 Sophgo Technology Inc.
6 * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com>
9 #include <linux/array_size.h>
10 #include <linux/bits.h>
11 #include <linux/clk.h>
12 #include <linux/clk-provider.h>
14 #include <linux/platform_device.h>
15 #include <asm/div64.h>
17 #include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
19 #include "clk-sg2042.h"
21 /* Registers defined in SYS_CTRL */
22 #define R_PLL_BEGIN 0xC0
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)
30 /* Registers defined in CLOCK */
31 #define R_CLKENREG0 0x00
32 #define R_CLKENREG1 0x04
33 #define R_CLKSELREG0 0x20
34 #define R_CLKDIVREG0 0x40
35 #define R_CLKDIVREG1 0x44
36 #define R_CLKDIVREG2 0x48
37 #define R_CLKDIVREG3 0x4C
38 #define R_CLKDIVREG4 0x50
39 #define R_CLKDIVREG5 0x54
40 #define R_CLKDIVREG6 0x58
41 #define R_CLKDIVREG7 0x5C
42 #define R_CLKDIVREG8 0x60
43 #define R_CLKDIVREG9 0x64
44 #define R_CLKDIVREG10 0x68
45 #define R_CLKDIVREG11 0x6C
46 #define R_CLKDIVREG12 0x70
47 #define R_CLKDIVREG13 0x74
48 #define R_CLKDIVREG14 0x78
49 #define R_CLKDIVREG15 0x7C
50 #define R_CLKDIVREG16 0x80
51 #define R_CLKDIVREG17 0x84
52 #define R_CLKDIVREG18 0x88
53 #define R_CLKDIVREG19 0x8C
54 #define R_CLKDIVREG20 0x90
55 #define R_CLKDIVREG21 0x94
56 #define R_CLKDIVREG22 0x98
57 #define R_CLKDIVREG23 0x9C
58 #define R_CLKDIVREG24 0xA0
59 #define R_CLKDIVREG25 0xA4
60 #define R_CLKDIVREG26 0xA8
61 #define R_CLKDIVREG27 0xAC
62 #define R_CLKDIVREG28 0xB0
63 #define R_CLKDIVREG29 0xB4
64 #define R_CLKDIVREG30 0xB8
66 /* All following shift value are the same for all DIV registers */
67 #define SHIFT_DIV_RESET_CTRL 0
68 #define SHIFT_DIV_FACTOR_SEL 3
69 #define SHIFT_DIV_FACTOR 16
72 * struct sg2042_divider_clock - Divider clock
73 * @hw: clk_hw for initialization
74 * @id: used to map clk_onecell_data
75 * @reg: used for readl/writel.
76 * **NOTE**: DIV registers are ALL in CLOCK!
77 * @lock: spinlock to protect register access, modification of
78 * frequency can only be served one at the time
79 * @offset_ctrl: offset of divider control registers
80 * @shift: shift of "Clock Divider Factor" in divider control register
81 * @width: width of "Clock Divider Factor" in divider control register
82 * @div_flags: private flags for this clock, not for framework-specific
83 * @initval: In the divider control register, we can configure whether
84 * to use the value of "Clock Divider Factor" or just use
85 * the initial value pre-configured by IC. BIT[3] controls
86 * this and by default (value is 0), means initial value
88 * **NOTE** that we cannot read the initial value (default
89 * value when poweron) and default value of "Clock Divider
90 * Factor" is zero, which I think is a hardware design flaw
91 * and should be sync-ed with the initial value. So in
92 * software we have to add a configuration item (initval)
93 * to manually configure this value and use it when BIT[3]
96 struct sg2042_divider_clock
{
102 /* protect register access */
112 #define to_sg2042_clk_divider(_hw) \
113 container_of(_hw, struct sg2042_divider_clock, hw)
116 * struct sg2042_gate_clock - Gate clock
117 * @hw: clk_hw for initialization
118 * @id: used to map clk_onecell_data
119 * @offset_enable: offset of gate enable registers
120 * @bit_idx: which bit in the register controls gating of this clock
122 struct sg2042_gate_clock
{
132 * struct sg2042_mux_clock - Mux clock
133 * @hw: clk_hw for initialization
134 * @id: used to map clk_onecell_data
135 * @offset_select: offset of mux selection registers
136 * **NOTE**: MUX registers are ALL in CLOCK!
137 * @shift: shift of "Clock Select" in mux selection register
138 * @width: width of "Clock Select" in mux selection register
139 * @clk_nb: used for notification
140 * @original_index: set by notifier callback
142 struct sg2042_mux_clock
{
151 struct notifier_block clk_nb
;
155 #define to_sg2042_mux_nb(_nb) container_of(_nb, struct sg2042_mux_clock, clk_nb)
157 static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw
*hw
,
158 unsigned long parent_rate
)
160 struct sg2042_divider_clock
*divider
= to_sg2042_clk_divider(hw
);
161 unsigned long ret_rate
;
164 if (!(readl(divider
->reg
) & BIT(SHIFT_DIV_FACTOR_SEL
))) {
165 val
= divider
->initval
;
167 val
= readl(divider
->reg
) >> divider
->shift
;
168 val
&= clk_div_mask(divider
->width
);
171 ret_rate
= divider_recalc_rate(hw
, parent_rate
, val
, NULL
,
172 divider
->div_flags
, divider
->width
);
174 pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n",
175 clk_hw_get_name(hw
), ret_rate
);
179 static long sg2042_clk_divider_round_rate(struct clk_hw
*hw
,
181 unsigned long *prate
)
183 struct sg2042_divider_clock
*divider
= to_sg2042_clk_divider(hw
);
184 unsigned long ret_rate
;
187 /* if read only, just return current value */
188 if (divider
->div_flags
& CLK_DIVIDER_READ_ONLY
) {
189 if (!(readl(divider
->reg
) & BIT(SHIFT_DIV_FACTOR_SEL
))) {
190 bestdiv
= divider
->initval
;
192 bestdiv
= readl(divider
->reg
) >> divider
->shift
;
193 bestdiv
&= clk_div_mask(divider
->width
);
195 ret_rate
= DIV_ROUND_UP_ULL((u64
)*prate
, bestdiv
);
197 ret_rate
= divider_round_rate(hw
, rate
, prate
, NULL
,
198 divider
->width
, divider
->div_flags
);
201 pr_debug("--> %s: divider_round_rate: val = %ld\n",
202 clk_hw_get_name(hw
), ret_rate
);
206 static int sg2042_clk_divider_set_rate(struct clk_hw
*hw
,
208 unsigned long parent_rate
)
210 struct sg2042_divider_clock
*divider
= to_sg2042_clk_divider(hw
);
211 unsigned long flags
= 0;
212 u32 val
, val2
, value
;
214 value
= divider_get_val(rate
, parent_rate
, NULL
,
215 divider
->width
, divider
->div_flags
);
218 spin_lock_irqsave(divider
->lock
, flags
);
220 __acquire(divider
->lock
);
223 * The sequence of clock frequency modification is:
224 * Assert to reset divider.
225 * Modify the value of Clock Divide Factor (and High Wide if needed).
226 * De-assert to restore divided clock with new frequency.
228 val
= readl(divider
->reg
);
231 val
&= ~BIT(SHIFT_DIV_RESET_CTRL
);
232 writel(val
, divider
->reg
);
234 if (divider
->div_flags
& CLK_DIVIDER_HIWORD_MASK
) {
235 val
= clk_div_mask(divider
->width
) << (divider
->shift
+ 16);
237 val
= readl(divider
->reg
);
238 val
&= ~(clk_div_mask(divider
->width
) << divider
->shift
);
240 val
|= value
<< divider
->shift
;
241 val
|= BIT(SHIFT_DIV_FACTOR_SEL
);
242 writel(val
, divider
->reg
);
246 val
|= BIT(SHIFT_DIV_RESET_CTRL
);
247 writel(val
, divider
->reg
);
250 spin_unlock_irqrestore(divider
->lock
, flags
);
252 __release(divider
->lock
);
254 pr_debug("--> %s: divider_set_rate: register val = 0x%x\n",
255 clk_hw_get_name(hw
), val2
);
259 static const struct clk_ops sg2042_clk_divider_ops
= {
260 .recalc_rate
= sg2042_clk_divider_recalc_rate
,
261 .round_rate
= sg2042_clk_divider_round_rate
,
262 .set_rate
= sg2042_clk_divider_set_rate
,
265 static const struct clk_ops sg2042_clk_divider_ro_ops
= {
266 .recalc_rate
= sg2042_clk_divider_recalc_rate
,
267 .round_rate
= sg2042_clk_divider_round_rate
,
271 * Clock initialization macro naming rules:
272 * FW: use CLK_HW_INIT_FW_NAME
273 * HW: use CLK_HW_INIT_HW
274 * HWS: use CLK_HW_INIT_HWS
275 * RO: means Read-Only
277 #define SG2042_DIV_FW(_id, _name, _parent, \
278 _r_ctrl, _shift, _width, \
279 _div_flag, _initval) { \
281 .hw.init = CLK_HW_INIT_FW_NAME( \
284 &sg2042_clk_divider_ops, \
286 .offset_ctrl = _r_ctrl, \
289 .div_flags = _div_flag, \
290 .initval = _initval, \
293 #define SG2042_DIV_FW_RO(_id, _name, _parent, \
294 _r_ctrl, _shift, _width, \
295 _div_flag, _initval) { \
297 .hw.init = CLK_HW_INIT_FW_NAME( \
300 &sg2042_clk_divider_ro_ops, \
302 .offset_ctrl = _r_ctrl, \
305 .div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY, \
306 .initval = _initval, \
309 #define SG2042_DIV_HW(_id, _name, _parent, \
310 _r_ctrl, _shift, _width, \
311 _div_flag, _initval) { \
313 .hw.init = CLK_HW_INIT_HW( \
316 &sg2042_clk_divider_ops, \
318 .offset_ctrl = _r_ctrl, \
321 .div_flags = _div_flag, \
322 .initval = _initval, \
325 #define SG2042_DIV_HW_RO(_id, _name, _parent, \
326 _r_ctrl, _shift, _width, \
327 _div_flag, _initval) { \
329 .hw.init = CLK_HW_INIT_HW( \
332 &sg2042_clk_divider_ro_ops, \
334 .offset_ctrl = _r_ctrl, \
337 .div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY, \
338 .initval = _initval, \
341 #define SG2042_DIV_HWS(_id, _name, _parent, \
342 _r_ctrl, _shift, _width, \
343 _div_flag, _initval) { \
345 .hw.init = CLK_HW_INIT_HWS( \
348 &sg2042_clk_divider_ops, \
350 .offset_ctrl = _r_ctrl, \
353 .div_flags = _div_flag, \
354 .initval = _initval, \
357 #define SG2042_DIV_HWS_RO(_id, _name, _parent, \
358 _r_ctrl, _shift, _width, \
359 _div_flag, _initval) { \
361 .hw.init = CLK_HW_INIT_HWS( \
364 &sg2042_clk_divider_ro_ops, \
366 .offset_ctrl = _r_ctrl, \
369 .div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY, \
370 .initval = _initval, \
373 #define SG2042_GATE_HWS(_id, _name, _parent, _flags, \
374 _r_enable, _bit_idx) { \
376 .hw.init = CLK_HW_INIT_HWS( \
381 .offset_enable = _r_enable, \
382 .bit_idx = _bit_idx, \
385 #define SG2042_GATE_HW(_id, _name, _parent, _flags, \
386 _r_enable, _bit_idx) { \
388 .hw.init = CLK_HW_INIT_HW( \
393 .offset_enable = _r_enable, \
394 .bit_idx = _bit_idx, \
397 #define SG2042_GATE_FW(_id, _name, _parent, _flags, \
398 _r_enable, _bit_idx) { \
400 .hw.init = CLK_HW_INIT_FW_NAME( \
405 .offset_enable = _r_enable, \
406 .bit_idx = _bit_idx, \
409 #define SG2042_MUX(_id, _name, _parents, _flags, _r_select, _shift, _width) { \
411 .hw.init = CLK_HW_INIT_PARENTS_HW( \
416 .offset_select = _r_select, \
422 * Clock items in the array are sorted according to the clock-tree diagram,
423 * from top to bottom, from upstream to downstream. Read TRM for details.
426 /* updated during probe/registration */
427 static const struct clk_hw
*clk_gate_ddr01_div0
[] = { NULL
};
428 static const struct clk_hw
*clk_gate_ddr01_div1
[] = { NULL
};
429 static const struct clk_hw
*clk_gate_ddr23_div0
[] = { NULL
};
430 static const struct clk_hw
*clk_gate_ddr23_div1
[] = { NULL
};
431 static const struct clk_hw
*clk_gate_rp_cpu_normal_div0
[] = { NULL
};
432 static const struct clk_hw
*clk_gate_rp_cpu_normal_div1
[] = { NULL
};
433 static const struct clk_hw
*clk_gate_axi_ddr_div0
[] = { NULL
};
434 static const struct clk_hw
*clk_gate_axi_ddr_div1
[] = { NULL
};
436 static const struct sg2042_gate_clock sg2042_gate_clks_level_1
[] = {
437 SG2042_GATE_FW(GATE_CLK_DDR01_DIV0
, "clk_gate_ddr01_div0", "dpll0",
438 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
,
440 SG2042_GATE_FW(GATE_CLK_DDR01_DIV1
, "clk_gate_ddr01_div1", "fpll",
444 SG2042_GATE_FW(GATE_CLK_DDR23_DIV0
, "clk_gate_ddr23_div0", "dpll1",
445 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
,
447 SG2042_GATE_FW(GATE_CLK_DDR23_DIV1
, "clk_gate_ddr23_div1", "fpll",
451 SG2042_GATE_FW(GATE_CLK_RP_CPU_NORMAL_DIV0
,
452 "clk_gate_rp_cpu_normal_div0", "mpll",
453 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
455 SG2042_GATE_FW(GATE_CLK_RP_CPU_NORMAL_DIV1
,
456 "clk_gate_rp_cpu_normal_div1", "fpll",
460 SG2042_GATE_FW(GATE_CLK_AXI_DDR_DIV0
, "clk_gate_axi_ddr_div0", "mpll",
461 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
463 SG2042_GATE_FW(GATE_CLK_AXI_DDR_DIV1
, "clk_gate_axi_ddr_div1", "fpll",
468 #define DEF_DIVFLAG (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO)
470 static struct sg2042_divider_clock sg2042_div_clks_level_1
[] = {
471 SG2042_DIV_HWS_RO(DIV_CLK_DPLL0_DDR01_0
,
472 "clk_div_ddr01_0", clk_gate_ddr01_div0
,
473 R_CLKDIVREG27
, 16, 5, DEF_DIVFLAG
, 1),
474 SG2042_DIV_HWS_RO(DIV_CLK_FPLL_DDR01_1
,
475 "clk_div_ddr01_1", clk_gate_ddr01_div1
,
476 R_CLKDIVREG28
, 16, 5, DEF_DIVFLAG
, 1),
478 SG2042_DIV_HWS_RO(DIV_CLK_DPLL1_DDR23_0
,
479 "clk_div_ddr23_0", clk_gate_ddr23_div0
,
480 R_CLKDIVREG29
, 16, 5, DEF_DIVFLAG
, 1),
481 SG2042_DIV_HWS_RO(DIV_CLK_FPLL_DDR23_1
,
482 "clk_div_ddr23_1", clk_gate_ddr23_div1
,
483 R_CLKDIVREG30
, 16, 5, DEF_DIVFLAG
, 1),
485 SG2042_DIV_HWS(DIV_CLK_MPLL_RP_CPU_NORMAL_0
,
486 "clk_div_rp_cpu_normal_0", clk_gate_rp_cpu_normal_div0
,
487 R_CLKDIVREG0
, 16, 5, DEF_DIVFLAG
, 1),
488 SG2042_DIV_HWS(DIV_CLK_FPLL_RP_CPU_NORMAL_1
,
489 "clk_div_rp_cpu_normal_1", clk_gate_rp_cpu_normal_div1
,
490 R_CLKDIVREG1
, 16, 5, DEF_DIVFLAG
, 1),
492 SG2042_DIV_HWS(DIV_CLK_MPLL_AXI_DDR_0
,
493 "clk_div_axi_ddr_0", clk_gate_axi_ddr_div0
,
494 R_CLKDIVREG25
, 16, 5, DEF_DIVFLAG
, 2),
495 SG2042_DIV_HWS(DIV_CLK_FPLL_AXI_DDR_1
,
496 "clk_div_axi_ddr_1", clk_gate_axi_ddr_div1
,
497 R_CLKDIVREG26
, 16, 5, DEF_DIVFLAG
, 1),
501 * Note: regarding names for mux clock, "0/1" or "div0/div1" means the
502 * first/second parent input source, not the register value.
504 * "clk_div_ddr01_0" is the name of Clock divider 0 control of DDR01, and
505 * "clk_gate_ddr01_div0" is the gate clock in front of the "clk_div_ddr01_0",
506 * they are both controlled by register CLKDIVREG27;
507 * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
508 * "clk_gate_ddr01_div1" is the gate clock in front of the "clk_div_ddr01_1",
509 * they are both controlled by register CLKDIVREG28;
510 * While for register value of mux selection, use Clock Select for DDR01’s clock
511 * as example, see CLKSELREG0, bit[2].
512 * 1: Select in_dpll0_clk as clock source, correspondng to the parent input
513 * source from "clk_div_ddr01_0".
514 * 0: Select in_fpll_clk as clock source, corresponding to the parent input
515 * source from "clk_div_ddr01_1".
516 * So we need a table to define the array of register values corresponding to
517 * the parent index and tell CCF about this when registering mux clock.
519 static const u32 sg2042_mux_table
[] = {1, 0};
521 /* Aliases just for easy reading */
522 #define clk_div_ddr01_0 (&sg2042_div_clks_level_1[0].hw)
523 #define clk_div_ddr01_1 (&sg2042_div_clks_level_1[1].hw)
524 #define clk_div_ddr23_0 (&sg2042_div_clks_level_1[2].hw)
525 #define clk_div_ddr23_1 (&sg2042_div_clks_level_1[3].hw)
526 #define clk_div_rp_cpu_normal_0 (&sg2042_div_clks_level_1[4].hw)
527 #define clk_div_rp_cpu_normal_1 (&sg2042_div_clks_level_1[5].hw)
528 #define clk_div_axi_ddr_0 (&sg2042_div_clks_level_1[6].hw)
529 #define clk_div_axi_ddr_1 (&sg2042_div_clks_level_1[7].hw)
531 static const struct clk_hw
*clk_mux_ddr01_p
[] = {
536 static const struct clk_hw
*clk_mux_ddr23_p
[] = {
541 static const struct clk_hw
*clk_mux_rp_cpu_normal_p
[] = {
542 clk_div_rp_cpu_normal_0
,
543 clk_div_rp_cpu_normal_1
,
546 static const struct clk_hw
*clk_mux_axi_ddr_p
[] = {
551 /* Mux clocks to be updated during probe/registration */
552 static const struct clk_hw
*clk_mux_ddr01
[] = { NULL
};
553 static const struct clk_hw
*clk_mux_ddr23
[] = { NULL
};
554 static const struct clk_hw
*clk_mux_rp_cpu_normal
[] = { NULL
};
555 static const struct clk_hw
*clk_mux_axi_ddr
[] = { NULL
};
557 static struct sg2042_mux_clock sg2042_mux_clks
[] = {
558 SG2042_MUX(MUX_CLK_DDR01
, "clk_mux_ddr01", clk_mux_ddr01_p
,
559 CLK_SET_RATE_PARENT
| CLK_SET_RATE_NO_REPARENT
| CLK_MUX_READ_ONLY
,
561 SG2042_MUX(MUX_CLK_DDR23
, "clk_mux_ddr23", clk_mux_ddr23_p
,
562 CLK_SET_RATE_PARENT
| CLK_SET_RATE_NO_REPARENT
| CLK_MUX_READ_ONLY
,
564 SG2042_MUX(MUX_CLK_RP_CPU_NORMAL
, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p
,
565 CLK_SET_RATE_PARENT
| CLK_SET_RATE_NO_REPARENT
,
567 SG2042_MUX(MUX_CLK_AXI_DDR
, "clk_mux_axi_ddr", clk_mux_axi_ddr_p
,
568 CLK_SET_RATE_PARENT
| CLK_SET_RATE_NO_REPARENT
,
572 /* Aliases just for easy reading */
573 #define clk_div_top_rp_cmn_div2 (&sg2042_div_clks_level_2[0].hw)
574 #define clk_div_50m_a53 (&sg2042_div_clks_level_2[1].hw)
575 #define clk_div_timer1 (&sg2042_div_clks_level_2[2].hw)
576 #define clk_div_timer2 (&sg2042_div_clks_level_2[3].hw)
577 #define clk_div_timer3 (&sg2042_div_clks_level_2[4].hw)
578 #define clk_div_timer4 (&sg2042_div_clks_level_2[5].hw)
579 #define clk_div_timer5 (&sg2042_div_clks_level_2[6].hw)
580 #define clk_div_timer6 (&sg2042_div_clks_level_2[7].hw)
581 #define clk_div_timer7 (&sg2042_div_clks_level_2[8].hw)
582 #define clk_div_timer8 (&sg2042_div_clks_level_2[9].hw)
583 #define clk_div_uart_500m (&sg2042_div_clks_level_2[10].hw)
584 #define clk_div_ahb_lpc (&sg2042_div_clks_level_2[11].hw)
585 #define clk_div_efuse (&sg2042_div_clks_level_2[12].hw)
586 #define clk_div_tx_eth0 (&sg2042_div_clks_level_2[13].hw)
587 #define clk_div_ptp_ref_i_eth0 (&sg2042_div_clks_level_2[14].hw)
588 #define clk_div_ref_eth0 (&sg2042_div_clks_level_2[15].hw)
589 #define clk_div_emmc (&sg2042_div_clks_level_2[16].hw)
590 #define clk_div_sd (&sg2042_div_clks_level_2[17].hw)
591 #define clk_div_top_axi0 (&sg2042_div_clks_level_2[18].hw)
592 #define clk_div_100k_emmc (&sg2042_div_clks_level_2[19].hw)
593 #define clk_div_100k_sd (&sg2042_div_clks_level_2[20].hw)
594 #define clk_div_gpio_db (&sg2042_div_clks_level_2[21].hw)
595 #define clk_div_top_axi_hsperi (&sg2042_div_clks_level_2[22].hw)
597 static struct sg2042_divider_clock sg2042_div_clks_level_2
[] = {
598 SG2042_DIV_HWS(DIV_CLK_FPLL_TOP_RP_CMN_DIV2
,
599 "clk_div_top_rp_cmn_div2", clk_mux_rp_cpu_normal
,
600 R_CLKDIVREG3
, 16, 16, DEF_DIVFLAG
, 2),
602 SG2042_DIV_FW(DIV_CLK_FPLL_50M_A53
, "clk_div_50m_a53", "fpll",
603 R_CLKDIVREG2
, 16, 8, DEF_DIVFLAG
, 20),
604 /* downstream of div_50m_a53 */
605 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER1
, "clk_div_timer1", clk_div_50m_a53
,
606 R_CLKDIVREG6
, 16, 16, DEF_DIVFLAG
, 1),
607 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER2
, "clk_div_timer2", clk_div_50m_a53
,
608 R_CLKDIVREG7
, 16, 16, DEF_DIVFLAG
, 1),
609 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER3
, "clk_div_timer3", clk_div_50m_a53
,
610 R_CLKDIVREG8
, 16, 16, DEF_DIVFLAG
, 1),
611 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER4
, "clk_div_timer4", clk_div_50m_a53
,
612 R_CLKDIVREG9
, 16, 16, DEF_DIVFLAG
, 1),
613 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER5
, "clk_div_timer5", clk_div_50m_a53
,
614 R_CLKDIVREG10
, 16, 16, DEF_DIVFLAG
, 1),
615 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER6
, "clk_div_timer6", clk_div_50m_a53
,
616 R_CLKDIVREG11
, 16, 16, DEF_DIVFLAG
, 1),
617 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER7
, "clk_div_timer7", clk_div_50m_a53
,
618 R_CLKDIVREG12
, 16, 16, DEF_DIVFLAG
, 1),
619 SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER8
, "clk_div_timer8", clk_div_50m_a53
,
620 R_CLKDIVREG13
, 16, 16, DEF_DIVFLAG
, 1),
623 * Set clk_div_uart_500m as RO, because the width of CLKDIVREG4 is too
624 * narrow for us to produce 115200. Use UART internal divider directly.
626 SG2042_DIV_FW_RO(DIV_CLK_FPLL_UART_500M
, "clk_div_uart_500m", "fpll",
627 R_CLKDIVREG4
, 16, 7, DEF_DIVFLAG
, 2),
628 SG2042_DIV_FW(DIV_CLK_FPLL_AHB_LPC
, "clk_div_ahb_lpc", "fpll",
629 R_CLKDIVREG5
, 16, 16, DEF_DIVFLAG
, 5),
630 SG2042_DIV_FW(DIV_CLK_FPLL_EFUSE
, "clk_div_efuse", "fpll",
631 R_CLKDIVREG14
, 16, 7, DEF_DIVFLAG
, 40),
632 SG2042_DIV_FW(DIV_CLK_FPLL_TX_ETH0
, "clk_div_tx_eth0", "fpll",
633 R_CLKDIVREG16
, 16, 11, DEF_DIVFLAG
, 8),
634 SG2042_DIV_FW(DIV_CLK_FPLL_PTP_REF_I_ETH0
,
635 "clk_div_ptp_ref_i_eth0", "fpll",
636 R_CLKDIVREG17
, 16, 8, DEF_DIVFLAG
, 20),
637 SG2042_DIV_FW(DIV_CLK_FPLL_REF_ETH0
, "clk_div_ref_eth0", "fpll",
638 R_CLKDIVREG18
, 16, 8, DEF_DIVFLAG
, 40),
639 SG2042_DIV_FW(DIV_CLK_FPLL_EMMC
, "clk_div_emmc", "fpll",
640 R_CLKDIVREG19
, 16, 5, DEF_DIVFLAG
, 10),
641 SG2042_DIV_FW(DIV_CLK_FPLL_SD
, "clk_div_sd", "fpll",
642 R_CLKDIVREG21
, 16, 5, DEF_DIVFLAG
, 10),
644 SG2042_DIV_FW(DIV_CLK_FPLL_TOP_AXI0
, "clk_div_top_axi0", "fpll",
645 R_CLKDIVREG23
, 16, 5, DEF_DIVFLAG
, 10),
646 /* downstream of div_top_axi0 */
647 SG2042_DIV_HW(DIV_CLK_FPLL_100K_EMMC
, "clk_div_100k_emmc", clk_div_top_axi0
,
648 R_CLKDIVREG20
, 16, 16, DEF_DIVFLAG
, 1000),
649 SG2042_DIV_HW(DIV_CLK_FPLL_100K_SD
, "clk_div_100k_sd", clk_div_top_axi0
,
650 R_CLKDIVREG22
, 16, 16, DEF_DIVFLAG
, 1000),
651 SG2042_DIV_HW(DIV_CLK_FPLL_GPIO_DB
, "clk_div_gpio_db", clk_div_top_axi0
,
652 R_CLKDIVREG15
, 16, 16, DEF_DIVFLAG
, 1000),
654 SG2042_DIV_FW(DIV_CLK_FPLL_TOP_AXI_HSPERI
,
655 "clk_div_top_axi_hsperi", "fpll",
656 R_CLKDIVREG24
, 16, 5, DEF_DIVFLAG
, 4),
659 /* Gate clocks to be updated during probe/registration */
660 static const struct clk_hw
*clk_gate_rp_cpu_normal
[] = { NULL
};
661 static const struct clk_hw
*clk_gate_top_rp_cmn_div2
[] = { NULL
};
663 static const struct sg2042_gate_clock sg2042_gate_clks_level_2
[] = {
664 SG2042_GATE_HWS(GATE_CLK_DDR01
, "clk_gate_ddr01", clk_mux_ddr01
,
665 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
668 SG2042_GATE_HWS(GATE_CLK_DDR23
, "clk_gate_ddr23", clk_mux_ddr23
,
669 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
672 SG2042_GATE_HWS(GATE_CLK_RP_CPU_NORMAL
,
673 "clk_gate_rp_cpu_normal", clk_mux_rp_cpu_normal
,
674 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
677 SG2042_GATE_HWS(GATE_CLK_AXI_DDR
, "clk_gate_axi_ddr", clk_mux_axi_ddr
,
678 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
681 /* upon are gate clocks directly downstream of muxes */
683 /* downstream of clk_div_top_rp_cmn_div2 */
684 SG2042_GATE_HW(GATE_CLK_TOP_RP_CMN_DIV2
,
685 "clk_gate_top_rp_cmn_div2", clk_div_top_rp_cmn_div2
,
686 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
, R_CLKENREG0
, 2),
687 SG2042_GATE_HWS(GATE_CLK_HSDMA
, "clk_gate_hsdma", clk_gate_top_rp_cmn_div2
,
688 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 10),
691 * downstream of clk_gate_rp_cpu_normal
693 * FIXME: there should be one 1/2 DIV between clk_gate_rp_cpu_normal
694 * and clk_gate_axi_pcie0/clk_gate_axi_pcie1.
695 * But the 1/2 DIV is fixed and no configurable register exported, so
696 * when reading from these two clocks, the rate value are still the
697 * same as that of clk_gate_rp_cpu_normal, it's not correct.
698 * This just affects the value read.
700 SG2042_GATE_HWS(GATE_CLK_AXI_PCIE0
,
701 "clk_gate_axi_pcie0", clk_gate_rp_cpu_normal
,
702 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
, R_CLKENREG1
, 8),
703 SG2042_GATE_HWS(GATE_CLK_AXI_PCIE1
,
704 "clk_gate_axi_pcie1", clk_gate_rp_cpu_normal
,
705 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
, R_CLKENREG1
, 9),
707 /* downstream of div_50m_a53 */
708 SG2042_GATE_HW(GATE_CLK_A53_50M
, "clk_gate_a53_50m", clk_div_50m_a53
,
709 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
, R_CLKENREG0
, 1),
710 SG2042_GATE_HW(GATE_CLK_TIMER1
, "clk_gate_timer1", clk_div_timer1
,
711 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 12),
712 SG2042_GATE_HW(GATE_CLK_TIMER2
, "clk_gate_timer2", clk_div_timer2
,
713 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 13),
714 SG2042_GATE_HW(GATE_CLK_TIMER3
, "clk_gate_timer3", clk_div_timer3
,
715 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 14),
716 SG2042_GATE_HW(GATE_CLK_TIMER4
, "clk_gate_timer4", clk_div_timer4
,
717 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 15),
718 SG2042_GATE_HW(GATE_CLK_TIMER5
, "clk_gate_timer5", clk_div_timer5
,
719 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 16),
720 SG2042_GATE_HW(GATE_CLK_TIMER6
, "clk_gate_timer6", clk_div_timer6
,
721 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 17),
722 SG2042_GATE_HW(GATE_CLK_TIMER7
, "clk_gate_timer7", clk_div_timer7
,
723 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 18),
724 SG2042_GATE_HW(GATE_CLK_TIMER8
, "clk_gate_timer8", clk_div_timer8
,
725 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 19),
727 /* gate clocks downstream from div clocks one-to-one */
728 SG2042_GATE_HW(GATE_CLK_UART_500M
, "clk_gate_uart_500m", clk_div_uart_500m
,
729 CLK_SET_RATE_PARENT
| CLK_IGNORE_UNUSED
, R_CLKENREG0
, 4),
730 SG2042_GATE_HW(GATE_CLK_AHB_LPC
, "clk_gate_ahb_lpc", clk_div_ahb_lpc
,
731 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 7),
732 SG2042_GATE_HW(GATE_CLK_EFUSE
, "clk_gate_efuse", clk_div_efuse
,
733 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 20),
734 SG2042_GATE_HW(GATE_CLK_TX_ETH0
, "clk_gate_tx_eth0", clk_div_tx_eth0
,
735 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 30),
736 SG2042_GATE_HW(GATE_CLK_PTP_REF_I_ETH0
,
737 "clk_gate_ptp_ref_i_eth0", clk_div_ptp_ref_i_eth0
,
738 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 0),
739 SG2042_GATE_HW(GATE_CLK_REF_ETH0
, "clk_gate_ref_eth0", clk_div_ref_eth0
,
740 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 1),
741 SG2042_GATE_HW(GATE_CLK_EMMC_100M
, "clk_gate_emmc", clk_div_emmc
,
742 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 3),
743 SG2042_GATE_HW(GATE_CLK_SD_100M
, "clk_gate_sd", clk_div_sd
,
744 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 6),
746 /* downstream of clk_div_top_axi0 */
747 SG2042_GATE_HW(GATE_CLK_AHB_ROM
, "clk_gate_ahb_rom", clk_div_top_axi0
,
749 SG2042_GATE_HW(GATE_CLK_AHB_SF
, "clk_gate_ahb_sf", clk_div_top_axi0
,
751 SG2042_GATE_HW(GATE_CLK_AXI_SRAM
, "clk_gate_axi_sram", clk_div_top_axi0
,
752 CLK_IGNORE_UNUSED
, R_CLKENREG0
, 10),
753 SG2042_GATE_HW(GATE_CLK_APB_TIMER
, "clk_gate_apb_timer", clk_div_top_axi0
,
754 CLK_IGNORE_UNUSED
, R_CLKENREG0
, 11),
755 SG2042_GATE_HW(GATE_CLK_APB_EFUSE
, "clk_gate_apb_efuse", clk_div_top_axi0
,
757 SG2042_GATE_HW(GATE_CLK_APB_GPIO
, "clk_gate_apb_gpio", clk_div_top_axi0
,
759 SG2042_GATE_HW(GATE_CLK_APB_GPIO_INTR
,
760 "clk_gate_apb_gpio_intr", clk_div_top_axi0
,
761 CLK_IS_CRITICAL
, R_CLKENREG0
, 23),
762 SG2042_GATE_HW(GATE_CLK_APB_I2C
, "clk_gate_apb_i2c", clk_div_top_axi0
,
764 SG2042_GATE_HW(GATE_CLK_APB_WDT
, "clk_gate_apb_wdt", clk_div_top_axi0
,
766 SG2042_GATE_HW(GATE_CLK_APB_PWM
, "clk_gate_apb_pwm", clk_div_top_axi0
,
768 SG2042_GATE_HW(GATE_CLK_APB_RTC
, "clk_gate_apb_rtc", clk_div_top_axi0
,
770 SG2042_GATE_HW(GATE_CLK_TOP_AXI0
, "clk_gate_top_axi0", clk_div_top_axi0
,
771 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
773 /* downstream of DIV clocks which are sourced from clk_div_top_axi0 */
774 SG2042_GATE_HW(GATE_CLK_GPIO_DB
, "clk_gate_gpio_db", clk_div_gpio_db
,
775 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 24),
776 SG2042_GATE_HW(GATE_CLK_100K_EMMC
, "clk_gate_100k_emmc", clk_div_100k_emmc
,
777 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 4),
778 SG2042_GATE_HW(GATE_CLK_100K_SD
, "clk_gate_100k_sd", clk_div_100k_sd
,
779 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 7),
781 /* downstream of clk_div_top_axi_hsperi */
782 SG2042_GATE_HW(GATE_CLK_SYSDMA_AXI
,
783 "clk_gate_sysdma_axi", clk_div_top_axi_hsperi
,
784 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 3),
785 SG2042_GATE_HW(GATE_CLK_APB_UART
,
786 "clk_gate_apb_uart", clk_div_top_axi_hsperi
,
787 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 5),
788 SG2042_GATE_HW(GATE_CLK_AXI_DBG_I2C
,
789 "clk_gate_axi_dbg_i2c", clk_div_top_axi_hsperi
,
790 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 6),
791 SG2042_GATE_HW(GATE_CLK_APB_SPI
,
792 "clk_gate_apb_spi", clk_div_top_axi_hsperi
,
793 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 25),
794 SG2042_GATE_HW(GATE_CLK_AXI_ETH0
,
795 "clk_gate_axi_eth0", clk_div_top_axi_hsperi
,
796 CLK_SET_RATE_PARENT
, R_CLKENREG0
, 31),
797 SG2042_GATE_HW(GATE_CLK_AXI_EMMC
,
798 "clk_gate_axi_emmc", clk_div_top_axi_hsperi
,
799 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 2),
800 SG2042_GATE_HW(GATE_CLK_AXI_SD
,
801 "clk_gate_axi_sd", clk_div_top_axi_hsperi
,
802 CLK_SET_RATE_PARENT
, R_CLKENREG1
, 5),
803 SG2042_GATE_HW(GATE_CLK_TOP_AXI_HSPERI
,
804 "clk_gate_top_axi_hsperi", clk_div_top_axi_hsperi
,
805 CLK_SET_RATE_PARENT
| CLK_IS_CRITICAL
,
809 static DEFINE_SPINLOCK(sg2042_clk_lock
);
811 static int sg2042_clk_register_divs(struct device
*dev
,
812 struct sg2042_clk_data
*clk_data
,
813 struct sg2042_divider_clock div_clks
[],
816 struct sg2042_divider_clock
*div
;
820 for (i
= 0; i
< num_div_clks
; i
++) {
823 if (div
->div_flags
& CLK_DIVIDER_HIWORD_MASK
) {
824 if (div
->width
+ div
->shift
> 16) {
825 pr_warn("divider value exceeds LOWORD field\n");
831 div
->reg
= clk_data
->iobase
+ div
->offset_ctrl
;
832 div
->lock
= &sg2042_clk_lock
;
835 ret
= devm_clk_hw_register(dev
, hw
);
837 pr_err("failed to register clock %s\n", div
->hw
.init
->name
);
841 clk_data
->onecell_data
.hws
[div
->id
] = hw
;
847 static int sg2042_clk_register_gates(struct device
*dev
,
848 struct sg2042_clk_data
*clk_data
,
849 const struct sg2042_gate_clock gate_clks
[],
852 const struct sg2042_gate_clock
*gate
;
856 for (i
= 0; i
< num_gate_clks
; i
++) {
857 gate
= &gate_clks
[i
];
858 hw
= __devm_clk_hw_register_gate
863 gate
->hw
.init
->parent_hws
[0],
865 gate
->hw
.init
->flags
,
866 clk_data
->iobase
+ gate
->offset_enable
,
871 pr_err("failed to register clock %s\n", gate
->hw
.init
->name
);
876 clk_data
->onecell_data
.hws
[gate
->id
] = hw
;
878 /* Updated some clocks which take the role of parent */
880 case GATE_CLK_RP_CPU_NORMAL
:
881 *clk_gate_rp_cpu_normal
= hw
;
883 case GATE_CLK_TOP_RP_CMN_DIV2
:
884 *clk_gate_top_rp_cmn_div2
= hw
;
892 static int sg2042_clk_register_gates_fw(struct device
*dev
,
893 struct sg2042_clk_data
*clk_data
,
894 const struct sg2042_gate_clock gate_clks
[],
897 const struct sg2042_gate_clock
*gate
;
901 for (i
= 0; i
< num_gate_clks
; i
++) {
902 gate
= &gate_clks
[i
];
903 hw
= devm_clk_hw_register_gate_parent_data
906 gate
->hw
.init
->parent_data
,
907 gate
->hw
.init
->flags
,
908 clk_data
->iobase
+ gate
->offset_enable
,
913 pr_err("failed to register clock %s\n", gate
->hw
.init
->name
);
918 clk_data
->onecell_data
.hws
[gate
->id
] = hw
;
920 /* Updated some clocks which take the role of parent */
922 case GATE_CLK_DDR01_DIV0
:
923 *clk_gate_ddr01_div0
= hw
;
925 case GATE_CLK_DDR01_DIV1
:
926 *clk_gate_ddr01_div1
= hw
;
928 case GATE_CLK_DDR23_DIV0
:
929 *clk_gate_ddr23_div0
= hw
;
931 case GATE_CLK_DDR23_DIV1
:
932 *clk_gate_ddr23_div1
= hw
;
934 case GATE_CLK_RP_CPU_NORMAL_DIV0
:
935 *clk_gate_rp_cpu_normal_div0
= hw
;
937 case GATE_CLK_RP_CPU_NORMAL_DIV1
:
938 *clk_gate_rp_cpu_normal_div1
= hw
;
940 case GATE_CLK_AXI_DDR_DIV0
:
941 *clk_gate_axi_ddr_div0
= hw
;
943 case GATE_CLK_AXI_DDR_DIV1
:
944 *clk_gate_axi_ddr_div1
= hw
;
952 static int sg2042_mux_notifier_cb(struct notifier_block
*nb
,
956 struct sg2042_mux_clock
*mux
= to_sg2042_mux_nb(nb
);
957 const struct clk_ops
*ops
= &clk_mux_ops
;
958 struct clk_notifier_data
*ndata
= data
;
962 hw
= __clk_get_hw(ndata
->clk
);
964 /* To switch to fpll before changing rate and restore after that */
965 if (event
== PRE_RATE_CHANGE
) {
966 mux
->original_index
= ops
->get_parent(hw
);
969 * "1" is the array index of the second parent input source of
970 * mux. For SG2042, it's fpll for all mux clocks.
971 * "0" is the array index of the frist parent input source of
972 * mux, For SG2042, it's mpll.
973 * FIXME, any good idea to avoid magic number?
975 if (mux
->original_index
== 0)
976 ret
= ops
->set_parent(hw
, 1);
977 } else if (event
== POST_RATE_CHANGE
) {
978 ret
= ops
->set_parent(hw
, mux
->original_index
);
981 return notifier_from_errno(ret
);
984 static int sg2042_clk_register_muxs(struct device
*dev
,
985 struct sg2042_clk_data
*clk_data
,
986 struct sg2042_mux_clock mux_clks
[],
989 struct sg2042_mux_clock
*mux
;
993 for (i
= 0; i
< num_mux_clks
; i
++) {
996 hw
= __devm_clk_hw_register_mux
1000 mux
->hw
.init
->num_parents
,
1002 mux
->hw
.init
->parent_hws
,
1004 mux
->hw
.init
->flags
,
1005 clk_data
->iobase
+ mux
->offset_select
,
1007 BIT(mux
->width
) - 1,
1012 pr_err("failed to register clock %s\n", mux
->hw
.init
->name
);
1017 clk_data
->onecell_data
.hws
[mux
->id
] = hw
;
1019 /* Updated some clocks which takes the role of parent */
1022 *clk_mux_ddr01
= hw
;
1025 *clk_mux_ddr23
= hw
;
1027 case MUX_CLK_RP_CPU_NORMAL
:
1028 *clk_mux_rp_cpu_normal
= hw
;
1030 case MUX_CLK_AXI_DDR
:
1031 *clk_mux_axi_ddr
= hw
;
1036 * FIXME: Theoretically, we should set parent for the
1037 * mux, but seems hardware has done this for us with
1038 * default value, so we don't set parent again here.
1041 if (!(mux
->hw
.init
->flags
& CLK_MUX_READ_ONLY
)) {
1042 mux
->clk_nb
.notifier_call
= sg2042_mux_notifier_cb
;
1043 ret
= devm_clk_notifier_register(dev
, hw
->clk
, &mux
->clk_nb
);
1045 pr_err("failed to register clock notifier for %s\n",
1046 mux
->hw
.init
->name
);
1055 static int sg2042_init_clkdata(struct platform_device
*pdev
,
1057 struct sg2042_clk_data
**pp_clk_data
)
1059 struct sg2042_clk_data
*clk_data
= NULL
;
1061 clk_data
= devm_kzalloc(&pdev
->dev
,
1062 struct_size(clk_data
, onecell_data
.hws
, num_clks
),
1067 clk_data
->iobase
= devm_platform_ioremap_resource(pdev
, 0);
1068 if (WARN_ON(IS_ERR(clk_data
->iobase
)))
1069 return PTR_ERR(clk_data
->iobase
);
1071 clk_data
->onecell_data
.num
= num_clks
;
1073 *pp_clk_data
= clk_data
;
1078 static int sg2042_clkgen_probe(struct platform_device
*pdev
)
1080 struct sg2042_clk_data
*clk_data
= NULL
;
1084 num_clks
= ARRAY_SIZE(sg2042_div_clks_level_1
) +
1085 ARRAY_SIZE(sg2042_div_clks_level_2
) +
1086 ARRAY_SIZE(sg2042_gate_clks_level_1
) +
1087 ARRAY_SIZE(sg2042_gate_clks_level_2
) +
1088 ARRAY_SIZE(sg2042_mux_clks
);
1090 ret
= sg2042_init_clkdata(pdev
, num_clks
, &clk_data
);
1095 ret
= sg2042_clk_register_gates_fw(&pdev
->dev
, clk_data
,
1096 sg2042_gate_clks_level_1
,
1097 ARRAY_SIZE(sg2042_gate_clks_level_1
));
1102 ret
= sg2042_clk_register_divs(&pdev
->dev
, clk_data
, sg2042_div_clks_level_1
,
1103 ARRAY_SIZE(sg2042_div_clks_level_1
));
1108 ret
= sg2042_clk_register_muxs(&pdev
->dev
, clk_data
, sg2042_mux_clks
,
1109 ARRAY_SIZE(sg2042_mux_clks
));
1114 ret
= sg2042_clk_register_divs(&pdev
->dev
, clk_data
, sg2042_div_clks_level_2
,
1115 ARRAY_SIZE(sg2042_div_clks_level_2
));
1120 ret
= sg2042_clk_register_gates(&pdev
->dev
, clk_data
, sg2042_gate_clks_level_2
,
1121 ARRAY_SIZE(sg2042_gate_clks_level_2
));
1125 return devm_of_clk_add_hw_provider(&pdev
->dev
,
1126 of_clk_hw_onecell_get
,
1127 &clk_data
->onecell_data
);
1130 pr_err("%s failed error number %d\n", __func__
, ret
);
1134 static const struct of_device_id sg2042_clkgen_match
[] = {
1135 { .compatible
= "sophgo,sg2042-clkgen" },
1138 MODULE_DEVICE_TABLE(of
, sg2042_clkgen_match
);
1140 static struct platform_driver sg2042_clkgen_driver
= {
1141 .probe
= sg2042_clkgen_probe
,
1143 .name
= "clk-sophgo-sg2042-clkgen",
1144 .of_match_table
= sg2042_clkgen_match
,
1145 .suppress_bind_attrs
= true,
1148 module_platform_driver(sg2042_clkgen_driver
);
1150 MODULE_AUTHOR("Chen Wang");
1151 MODULE_DESCRIPTION("Sophgo SG2042 clock generator driver");
1152 MODULE_LICENSE("GPL");