xref: /linux/drivers/clk/sophgo/clk-sg2042-clkgen.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1*48cf7e01SChen Wang // SPDX-License-Identifier: GPL-2.0
2*48cf7e01SChen Wang /*
3*48cf7e01SChen Wang  * Sophgo SG2042 Clock Generator Driver
4*48cf7e01SChen Wang  *
5*48cf7e01SChen Wang  * Copyright (C) 2024 Sophgo Technology Inc.
6*48cf7e01SChen Wang  * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com>
7*48cf7e01SChen Wang  */
8*48cf7e01SChen Wang 
9*48cf7e01SChen Wang #include <linux/array_size.h>
10*48cf7e01SChen Wang #include <linux/bits.h>
11*48cf7e01SChen Wang #include <linux/clk.h>
12*48cf7e01SChen Wang #include <linux/clk-provider.h>
13*48cf7e01SChen Wang #include <linux/io.h>
14*48cf7e01SChen Wang #include <linux/platform_device.h>
15*48cf7e01SChen Wang #include <asm/div64.h>
16*48cf7e01SChen Wang 
17*48cf7e01SChen Wang #include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
18*48cf7e01SChen Wang 
19*48cf7e01SChen Wang #include "clk-sg2042.h"
20*48cf7e01SChen Wang 
21*48cf7e01SChen Wang /* Registers defined in SYS_CTRL */
22*48cf7e01SChen Wang #define R_PLL_BEGIN		0xC0
23*48cf7e01SChen Wang #define R_PLL_STAT		(0xC0 - R_PLL_BEGIN)
24*48cf7e01SChen Wang #define R_PLL_CLKEN_CONTROL	(0xC4 - R_PLL_BEGIN)
25*48cf7e01SChen Wang #define R_MPLL_CONTROL		(0xE8 - R_PLL_BEGIN)
26*48cf7e01SChen Wang #define R_FPLL_CONTROL		(0xF4 - R_PLL_BEGIN)
27*48cf7e01SChen Wang #define R_DPLL0_CONTROL		(0xF8 - R_PLL_BEGIN)
28*48cf7e01SChen Wang #define R_DPLL1_CONTROL		(0xFC - R_PLL_BEGIN)
29*48cf7e01SChen Wang 
30*48cf7e01SChen Wang /* Registers defined in CLOCK */
31*48cf7e01SChen Wang #define R_CLKENREG0		0x00
32*48cf7e01SChen Wang #define R_CLKENREG1		0x04
33*48cf7e01SChen Wang #define R_CLKSELREG0		0x20
34*48cf7e01SChen Wang #define R_CLKDIVREG0		0x40
35*48cf7e01SChen Wang #define R_CLKDIVREG1		0x44
36*48cf7e01SChen Wang #define R_CLKDIVREG2		0x48
37*48cf7e01SChen Wang #define R_CLKDIVREG3		0x4C
38*48cf7e01SChen Wang #define R_CLKDIVREG4		0x50
39*48cf7e01SChen Wang #define R_CLKDIVREG5		0x54
40*48cf7e01SChen Wang #define R_CLKDIVREG6		0x58
41*48cf7e01SChen Wang #define R_CLKDIVREG7		0x5C
42*48cf7e01SChen Wang #define R_CLKDIVREG8		0x60
43*48cf7e01SChen Wang #define R_CLKDIVREG9		0x64
44*48cf7e01SChen Wang #define R_CLKDIVREG10		0x68
45*48cf7e01SChen Wang #define R_CLKDIVREG11		0x6C
46*48cf7e01SChen Wang #define R_CLKDIVREG12		0x70
47*48cf7e01SChen Wang #define R_CLKDIVREG13		0x74
48*48cf7e01SChen Wang #define R_CLKDIVREG14		0x78
49*48cf7e01SChen Wang #define R_CLKDIVREG15		0x7C
50*48cf7e01SChen Wang #define R_CLKDIVREG16		0x80
51*48cf7e01SChen Wang #define R_CLKDIVREG17		0x84
52*48cf7e01SChen Wang #define R_CLKDIVREG18		0x88
53*48cf7e01SChen Wang #define R_CLKDIVREG19		0x8C
54*48cf7e01SChen Wang #define R_CLKDIVREG20		0x90
55*48cf7e01SChen Wang #define R_CLKDIVREG21		0x94
56*48cf7e01SChen Wang #define R_CLKDIVREG22		0x98
57*48cf7e01SChen Wang #define R_CLKDIVREG23		0x9C
58*48cf7e01SChen Wang #define R_CLKDIVREG24		0xA0
59*48cf7e01SChen Wang #define R_CLKDIVREG25		0xA4
60*48cf7e01SChen Wang #define R_CLKDIVREG26		0xA8
61*48cf7e01SChen Wang #define R_CLKDIVREG27		0xAC
62*48cf7e01SChen Wang #define R_CLKDIVREG28		0xB0
63*48cf7e01SChen Wang #define R_CLKDIVREG29		0xB4
64*48cf7e01SChen Wang #define R_CLKDIVREG30		0xB8
65*48cf7e01SChen Wang 
66*48cf7e01SChen Wang /* All following shift value are the same for all DIV registers */
67*48cf7e01SChen Wang #define SHIFT_DIV_RESET_CTRL	0
68*48cf7e01SChen Wang #define SHIFT_DIV_FACTOR_SEL	3
69*48cf7e01SChen Wang #define SHIFT_DIV_FACTOR	16
70*48cf7e01SChen Wang 
71*48cf7e01SChen Wang /**
72*48cf7e01SChen Wang  * struct sg2042_divider_clock - Divider clock
73*48cf7e01SChen Wang  * @hw:			clk_hw for initialization
74*48cf7e01SChen Wang  * @id:			used to map clk_onecell_data
75*48cf7e01SChen Wang  * @reg:		used for readl/writel.
76*48cf7e01SChen Wang  *			**NOTE**: DIV registers are ALL in CLOCK!
77*48cf7e01SChen Wang  * @lock:		spinlock to protect register access, modification of
78*48cf7e01SChen Wang  *			frequency can only be served one at the time
79*48cf7e01SChen Wang  * @offset_ctrl:	offset of divider control registers
80*48cf7e01SChen Wang  * @shift:		shift of "Clock Divider Factor" in divider control register
81*48cf7e01SChen Wang  * @width:		width of "Clock Divider Factor" in divider control register
82*48cf7e01SChen Wang  * @div_flags:		private flags for this clock, not for framework-specific
83*48cf7e01SChen Wang  * @initval:		In the divider control register, we can configure whether
84*48cf7e01SChen Wang  *			to use the value of "Clock Divider Factor" or just use
85*48cf7e01SChen Wang  *			the initial value pre-configured by IC. BIT[3] controls
86*48cf7e01SChen Wang  *			this and by default (value is 0), means initial value
87*48cf7e01SChen Wang  *			is used.
88*48cf7e01SChen Wang  *			**NOTE** that we cannot read the initial value (default
89*48cf7e01SChen Wang  *			value when poweron) and default value of "Clock Divider
90*48cf7e01SChen Wang  *			Factor" is zero, which I think is a hardware design flaw
91*48cf7e01SChen Wang  *			and should be sync-ed with the initial value. So in
92*48cf7e01SChen Wang  *			software we have to add a configuration item (initval)
93*48cf7e01SChen Wang  *			to manually configure this value and use it when BIT[3]
94*48cf7e01SChen Wang  *			is zero.
95*48cf7e01SChen Wang  */
96*48cf7e01SChen Wang struct sg2042_divider_clock {
97*48cf7e01SChen Wang 	struct clk_hw hw;
98*48cf7e01SChen Wang 
99*48cf7e01SChen Wang 	unsigned int id;
100*48cf7e01SChen Wang 
101*48cf7e01SChen Wang 	void __iomem *reg;
102*48cf7e01SChen Wang 	/* protect register access */
103*48cf7e01SChen Wang 	spinlock_t *lock;
104*48cf7e01SChen Wang 
105*48cf7e01SChen Wang 	u32 offset_ctrl;
106*48cf7e01SChen Wang 	u8 shift;
107*48cf7e01SChen Wang 	u8 width;
108*48cf7e01SChen Wang 	u8 div_flags;
109*48cf7e01SChen Wang 	u32 initval;
110*48cf7e01SChen Wang };
111*48cf7e01SChen Wang 
112*48cf7e01SChen Wang #define to_sg2042_clk_divider(_hw)	\
113*48cf7e01SChen Wang 	container_of(_hw, struct sg2042_divider_clock, hw)
114*48cf7e01SChen Wang 
115*48cf7e01SChen Wang /**
116*48cf7e01SChen Wang  * struct sg2042_gate_clock - Gate clock
117*48cf7e01SChen Wang  * @hw:			clk_hw for initialization
118*48cf7e01SChen Wang  * @id:			used to map clk_onecell_data
119*48cf7e01SChen Wang  * @offset_enable:	offset of gate enable registers
120*48cf7e01SChen Wang  * @bit_idx:		which bit in the register controls gating of this clock
121*48cf7e01SChen Wang  */
122*48cf7e01SChen Wang struct sg2042_gate_clock {
123*48cf7e01SChen Wang 	struct clk_hw hw;
124*48cf7e01SChen Wang 
125*48cf7e01SChen Wang 	unsigned int id;
126*48cf7e01SChen Wang 
127*48cf7e01SChen Wang 	u32 offset_enable;
128*48cf7e01SChen Wang 	u8 bit_idx;
129*48cf7e01SChen Wang };
130*48cf7e01SChen Wang 
131*48cf7e01SChen Wang /**
132*48cf7e01SChen Wang  * struct sg2042_mux_clock - Mux clock
133*48cf7e01SChen Wang  * @hw:			clk_hw for initialization
134*48cf7e01SChen Wang  * @id:			used to map clk_onecell_data
135*48cf7e01SChen Wang  * @offset_select:	offset of mux selection registers
136*48cf7e01SChen Wang  *			**NOTE**: MUX registers are ALL in CLOCK!
137*48cf7e01SChen Wang  * @shift:		shift of "Clock Select" in mux selection register
138*48cf7e01SChen Wang  * @width:		width of "Clock Select" in mux selection register
139*48cf7e01SChen Wang  * @clk_nb:		used for notification
140*48cf7e01SChen Wang  * @original_index:	set by notifier callback
141*48cf7e01SChen Wang  */
142*48cf7e01SChen Wang struct sg2042_mux_clock {
143*48cf7e01SChen Wang 	struct clk_hw hw;
144*48cf7e01SChen Wang 
145*48cf7e01SChen Wang 	unsigned int id;
146*48cf7e01SChen Wang 
147*48cf7e01SChen Wang 	u32 offset_select;
148*48cf7e01SChen Wang 	u8 shift;
149*48cf7e01SChen Wang 	u8 width;
150*48cf7e01SChen Wang 
151*48cf7e01SChen Wang 	struct notifier_block clk_nb;
152*48cf7e01SChen Wang 	u8 original_index;
153*48cf7e01SChen Wang };
154*48cf7e01SChen Wang 
155*48cf7e01SChen Wang #define to_sg2042_mux_nb(_nb) container_of(_nb, struct sg2042_mux_clock, clk_nb)
156*48cf7e01SChen Wang 
sg2042_clk_divider_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)157*48cf7e01SChen Wang static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw *hw,
158*48cf7e01SChen Wang 						    unsigned long parent_rate)
159*48cf7e01SChen Wang {
160*48cf7e01SChen Wang 	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
161*48cf7e01SChen Wang 	unsigned long ret_rate;
162*48cf7e01SChen Wang 	u32 val;
163*48cf7e01SChen Wang 
164*48cf7e01SChen Wang 	if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) {
165*48cf7e01SChen Wang 		val = divider->initval;
166*48cf7e01SChen Wang 	} else {
167*48cf7e01SChen Wang 		val = readl(divider->reg) >> divider->shift;
168*48cf7e01SChen Wang 		val &= clk_div_mask(divider->width);
169*48cf7e01SChen Wang 	}
170*48cf7e01SChen Wang 
171*48cf7e01SChen Wang 	ret_rate = divider_recalc_rate(hw, parent_rate, val, NULL,
172*48cf7e01SChen Wang 				       divider->div_flags, divider->width);
173*48cf7e01SChen Wang 
174*48cf7e01SChen Wang 	pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n",
175*48cf7e01SChen Wang 		 clk_hw_get_name(hw), ret_rate);
176*48cf7e01SChen Wang 	return ret_rate;
177*48cf7e01SChen Wang }
178*48cf7e01SChen Wang 
sg2042_clk_divider_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)179*48cf7e01SChen Wang static long sg2042_clk_divider_round_rate(struct clk_hw *hw,
180*48cf7e01SChen Wang 					  unsigned long rate,
181*48cf7e01SChen Wang 					  unsigned long *prate)
182*48cf7e01SChen Wang {
183*48cf7e01SChen Wang 	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
184*48cf7e01SChen Wang 	unsigned long ret_rate;
185*48cf7e01SChen Wang 	u32 bestdiv;
186*48cf7e01SChen Wang 
187*48cf7e01SChen Wang 	/* if read only, just return current value */
188*48cf7e01SChen Wang 	if (divider->div_flags & CLK_DIVIDER_READ_ONLY) {
189*48cf7e01SChen Wang 		if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) {
190*48cf7e01SChen Wang 			bestdiv = divider->initval;
191*48cf7e01SChen Wang 		} else {
192*48cf7e01SChen Wang 			bestdiv = readl(divider->reg) >> divider->shift;
193*48cf7e01SChen Wang 			bestdiv &= clk_div_mask(divider->width);
194*48cf7e01SChen Wang 		}
195*48cf7e01SChen Wang 		ret_rate = DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
196*48cf7e01SChen Wang 	} else {
197*48cf7e01SChen Wang 		ret_rate = divider_round_rate(hw, rate, prate, NULL,
198*48cf7e01SChen Wang 					      divider->width, divider->div_flags);
199*48cf7e01SChen Wang 	}
200*48cf7e01SChen Wang 
201*48cf7e01SChen Wang 	pr_debug("--> %s: divider_round_rate: val = %ld\n",
202*48cf7e01SChen Wang 		 clk_hw_get_name(hw), ret_rate);
203*48cf7e01SChen Wang 	return ret_rate;
204*48cf7e01SChen Wang }
205*48cf7e01SChen Wang 
sg2042_clk_divider_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)206*48cf7e01SChen Wang static int sg2042_clk_divider_set_rate(struct clk_hw *hw,
207*48cf7e01SChen Wang 				       unsigned long rate,
208*48cf7e01SChen Wang 				       unsigned long parent_rate)
209*48cf7e01SChen Wang {
210*48cf7e01SChen Wang 	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
211*48cf7e01SChen Wang 	unsigned long flags = 0;
212*48cf7e01SChen Wang 	u32 val, val2, value;
213*48cf7e01SChen Wang 
214*48cf7e01SChen Wang 	value = divider_get_val(rate, parent_rate, NULL,
215*48cf7e01SChen Wang 				divider->width, divider->div_flags);
216*48cf7e01SChen Wang 
217*48cf7e01SChen Wang 	if (divider->lock)
218*48cf7e01SChen Wang 		spin_lock_irqsave(divider->lock, flags);
219*48cf7e01SChen Wang 	else
220*48cf7e01SChen Wang 		__acquire(divider->lock);
221*48cf7e01SChen Wang 
222*48cf7e01SChen Wang 	/*
223*48cf7e01SChen Wang 	 * The sequence of clock frequency modification is:
224*48cf7e01SChen Wang 	 * Assert to reset divider.
225*48cf7e01SChen Wang 	 * Modify the value of Clock Divide Factor (and High Wide if needed).
226*48cf7e01SChen Wang 	 * De-assert to restore divided clock with new frequency.
227*48cf7e01SChen Wang 	 */
228*48cf7e01SChen Wang 	val = readl(divider->reg);
229*48cf7e01SChen Wang 
230*48cf7e01SChen Wang 	/* assert */
231*48cf7e01SChen Wang 	val &= ~BIT(SHIFT_DIV_RESET_CTRL);
232*48cf7e01SChen Wang 	writel(val, divider->reg);
233*48cf7e01SChen Wang 
234*48cf7e01SChen Wang 	if (divider->div_flags & CLK_DIVIDER_HIWORD_MASK) {
235*48cf7e01SChen Wang 		val = clk_div_mask(divider->width) << (divider->shift + 16);
236*48cf7e01SChen Wang 	} else {
237*48cf7e01SChen Wang 		val = readl(divider->reg);
238*48cf7e01SChen Wang 		val &= ~(clk_div_mask(divider->width) << divider->shift);
239*48cf7e01SChen Wang 	}
240*48cf7e01SChen Wang 	val |= value << divider->shift;
241*48cf7e01SChen Wang 	val |= BIT(SHIFT_DIV_FACTOR_SEL);
242*48cf7e01SChen Wang 	writel(val, divider->reg);
243*48cf7e01SChen Wang 	val2 = val;
244*48cf7e01SChen Wang 
245*48cf7e01SChen Wang 	/* de-assert */
246*48cf7e01SChen Wang 	val |= BIT(SHIFT_DIV_RESET_CTRL);
247*48cf7e01SChen Wang 	writel(val, divider->reg);
248*48cf7e01SChen Wang 
249*48cf7e01SChen Wang 	if (divider->lock)
250*48cf7e01SChen Wang 		spin_unlock_irqrestore(divider->lock, flags);
251*48cf7e01SChen Wang 	else
252*48cf7e01SChen Wang 		__release(divider->lock);
253*48cf7e01SChen Wang 
254*48cf7e01SChen Wang 	pr_debug("--> %s: divider_set_rate: register val = 0x%x\n",
255*48cf7e01SChen Wang 		 clk_hw_get_name(hw), val2);
256*48cf7e01SChen Wang 	return 0;
257*48cf7e01SChen Wang }
258*48cf7e01SChen Wang 
259*48cf7e01SChen Wang static const struct clk_ops sg2042_clk_divider_ops = {
260*48cf7e01SChen Wang 	.recalc_rate = sg2042_clk_divider_recalc_rate,
261*48cf7e01SChen Wang 	.round_rate = sg2042_clk_divider_round_rate,
262*48cf7e01SChen Wang 	.set_rate = sg2042_clk_divider_set_rate,
263*48cf7e01SChen Wang };
264*48cf7e01SChen Wang 
265*48cf7e01SChen Wang static const struct clk_ops sg2042_clk_divider_ro_ops = {
266*48cf7e01SChen Wang 	.recalc_rate = sg2042_clk_divider_recalc_rate,
267*48cf7e01SChen Wang 	.round_rate = sg2042_clk_divider_round_rate,
268*48cf7e01SChen Wang };
269*48cf7e01SChen Wang 
270*48cf7e01SChen Wang /*
271*48cf7e01SChen Wang  * Clock initialization macro naming rules:
272*48cf7e01SChen Wang  * FW: use CLK_HW_INIT_FW_NAME
273*48cf7e01SChen Wang  * HW: use CLK_HW_INIT_HW
274*48cf7e01SChen Wang  * HWS: use CLK_HW_INIT_HWS
275*48cf7e01SChen Wang  * RO: means Read-Only
276*48cf7e01SChen Wang  */
277*48cf7e01SChen Wang #define SG2042_DIV_FW(_id, _name, _parent,				\
278*48cf7e01SChen Wang 		      _r_ctrl, _shift, _width,				\
279*48cf7e01SChen Wang 		      _div_flag, _initval) {				\
280*48cf7e01SChen Wang 		.id = _id,						\
281*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_FW_NAME(				\
282*48cf7e01SChen Wang 				_name,					\
283*48cf7e01SChen Wang 				_parent,				\
284*48cf7e01SChen Wang 				&sg2042_clk_divider_ops,		\
285*48cf7e01SChen Wang 				0),					\
286*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
287*48cf7e01SChen Wang 		.shift = _shift,					\
288*48cf7e01SChen Wang 		.width = _width,					\
289*48cf7e01SChen Wang 		.div_flags = _div_flag,					\
290*48cf7e01SChen Wang 		.initval = _initval,					\
291*48cf7e01SChen Wang 	}
292*48cf7e01SChen Wang 
293*48cf7e01SChen Wang #define SG2042_DIV_FW_RO(_id, _name, _parent,				\
294*48cf7e01SChen Wang 		  _r_ctrl, _shift, _width,				\
295*48cf7e01SChen Wang 		  _div_flag, _initval) {				\
296*48cf7e01SChen Wang 		.id = _id,						\
297*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_FW_NAME(				\
298*48cf7e01SChen Wang 				_name,					\
299*48cf7e01SChen Wang 				_parent,				\
300*48cf7e01SChen Wang 				&sg2042_clk_divider_ro_ops,		\
301*48cf7e01SChen Wang 				0),					\
302*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
303*48cf7e01SChen Wang 		.shift = _shift,					\
304*48cf7e01SChen Wang 		.width = _width,					\
305*48cf7e01SChen Wang 		.div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY,	\
306*48cf7e01SChen Wang 		.initval = _initval,					\
307*48cf7e01SChen Wang 	}
308*48cf7e01SChen Wang 
309*48cf7e01SChen Wang #define SG2042_DIV_HW(_id, _name, _parent,				\
310*48cf7e01SChen Wang 		      _r_ctrl, _shift, _width,				\
311*48cf7e01SChen Wang 		      _div_flag, _initval) {				\
312*48cf7e01SChen Wang 		.id = _id,						\
313*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HW(				\
314*48cf7e01SChen Wang 				_name,					\
315*48cf7e01SChen Wang 				_parent,				\
316*48cf7e01SChen Wang 				&sg2042_clk_divider_ops,		\
317*48cf7e01SChen Wang 				0),					\
318*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
319*48cf7e01SChen Wang 		.shift = _shift,					\
320*48cf7e01SChen Wang 		.width = _width,					\
321*48cf7e01SChen Wang 		.div_flags = _div_flag,					\
322*48cf7e01SChen Wang 		.initval = _initval,					\
323*48cf7e01SChen Wang 	}
324*48cf7e01SChen Wang 
325*48cf7e01SChen Wang #define SG2042_DIV_HW_RO(_id, _name, _parent,				\
326*48cf7e01SChen Wang 			 _r_ctrl, _shift, _width,			\
327*48cf7e01SChen Wang 			 _div_flag, _initval) {				\
328*48cf7e01SChen Wang 		.id = _id,						\
329*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HW(				\
330*48cf7e01SChen Wang 				_name,					\
331*48cf7e01SChen Wang 				_parent,				\
332*48cf7e01SChen Wang 				&sg2042_clk_divider_ro_ops,		\
333*48cf7e01SChen Wang 				0),					\
334*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
335*48cf7e01SChen Wang 		.shift = _shift,					\
336*48cf7e01SChen Wang 		.width = _width,					\
337*48cf7e01SChen Wang 		.div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY,	\
338*48cf7e01SChen Wang 		.initval = _initval,					\
339*48cf7e01SChen Wang 	}
340*48cf7e01SChen Wang 
341*48cf7e01SChen Wang #define SG2042_DIV_HWS(_id, _name, _parent,				\
342*48cf7e01SChen Wang 		       _r_ctrl, _shift, _width,				\
343*48cf7e01SChen Wang 		       _div_flag, _initval) {				\
344*48cf7e01SChen Wang 		.id = _id,						\
345*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HWS(				\
346*48cf7e01SChen Wang 				_name,					\
347*48cf7e01SChen Wang 				_parent,				\
348*48cf7e01SChen Wang 				&sg2042_clk_divider_ops,		\
349*48cf7e01SChen Wang 				0),					\
350*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
351*48cf7e01SChen Wang 		.shift = _shift,					\
352*48cf7e01SChen Wang 		.width = _width,					\
353*48cf7e01SChen Wang 		.div_flags = _div_flag,					\
354*48cf7e01SChen Wang 		.initval = _initval,					\
355*48cf7e01SChen Wang 	}
356*48cf7e01SChen Wang 
357*48cf7e01SChen Wang #define SG2042_DIV_HWS_RO(_id, _name, _parent,				\
358*48cf7e01SChen Wang 			  _r_ctrl, _shift, _width,			\
359*48cf7e01SChen Wang 			  _div_flag, _initval) {			\
360*48cf7e01SChen Wang 		.id = _id,						\
361*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HWS(				\
362*48cf7e01SChen Wang 				_name,					\
363*48cf7e01SChen Wang 				_parent,				\
364*48cf7e01SChen Wang 				&sg2042_clk_divider_ro_ops,		\
365*48cf7e01SChen Wang 				0),					\
366*48cf7e01SChen Wang 		.offset_ctrl = _r_ctrl,					\
367*48cf7e01SChen Wang 		.shift = _shift,					\
368*48cf7e01SChen Wang 		.width = _width,					\
369*48cf7e01SChen Wang 		.div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY,	\
370*48cf7e01SChen Wang 		.initval = _initval,					\
371*48cf7e01SChen Wang 	}
372*48cf7e01SChen Wang 
373*48cf7e01SChen Wang #define SG2042_GATE_HWS(_id, _name, _parent, _flags,	\
374*48cf7e01SChen Wang 			_r_enable, _bit_idx) {		\
375*48cf7e01SChen Wang 		.id = _id,				\
376*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HWS(		\
377*48cf7e01SChen Wang 				_name,			\
378*48cf7e01SChen Wang 				_parent,		\
379*48cf7e01SChen Wang 				NULL,			\
380*48cf7e01SChen Wang 				_flags),		\
381*48cf7e01SChen Wang 		.offset_enable = _r_enable,		\
382*48cf7e01SChen Wang 		.bit_idx = _bit_idx,			\
383*48cf7e01SChen Wang 	}
384*48cf7e01SChen Wang 
385*48cf7e01SChen Wang #define SG2042_GATE_HW(_id, _name, _parent, _flags,	\
386*48cf7e01SChen Wang 		       _r_enable, _bit_idx) {		\
387*48cf7e01SChen Wang 		.id = _id,				\
388*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_HW(		\
389*48cf7e01SChen Wang 				_name,			\
390*48cf7e01SChen Wang 				_parent,		\
391*48cf7e01SChen Wang 				NULL,			\
392*48cf7e01SChen Wang 				_flags),		\
393*48cf7e01SChen Wang 		.offset_enable = _r_enable,		\
394*48cf7e01SChen Wang 		.bit_idx = _bit_idx,			\
395*48cf7e01SChen Wang 	}
396*48cf7e01SChen Wang 
397*48cf7e01SChen Wang #define SG2042_GATE_FW(_id, _name, _parent, _flags,	\
398*48cf7e01SChen Wang 		       _r_enable, _bit_idx) {		\
399*48cf7e01SChen Wang 		.id = _id,				\
400*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_FW_NAME(		\
401*48cf7e01SChen Wang 				_name,			\
402*48cf7e01SChen Wang 				_parent,		\
403*48cf7e01SChen Wang 				NULL,			\
404*48cf7e01SChen Wang 				_flags),		\
405*48cf7e01SChen Wang 		.offset_enable = _r_enable,		\
406*48cf7e01SChen Wang 		.bit_idx = _bit_idx,			\
407*48cf7e01SChen Wang 	}
408*48cf7e01SChen Wang 
409*48cf7e01SChen Wang #define SG2042_MUX(_id, _name, _parents, _flags, _r_select, _shift, _width) { \
410*48cf7e01SChen Wang 		.id = _id,					\
411*48cf7e01SChen Wang 		.hw.init = CLK_HW_INIT_PARENTS_HW(		\
412*48cf7e01SChen Wang 				_name,				\
413*48cf7e01SChen Wang 				_parents,			\
414*48cf7e01SChen Wang 				NULL,				\
415*48cf7e01SChen Wang 				_flags),			\
416*48cf7e01SChen Wang 		.offset_select = _r_select,			\
417*48cf7e01SChen Wang 		.shift = _shift,				\
418*48cf7e01SChen Wang 		.width = _width,				\
419*48cf7e01SChen Wang 	}
420*48cf7e01SChen Wang 
421*48cf7e01SChen Wang /*
422*48cf7e01SChen Wang  * Clock items in the array are sorted according to the clock-tree diagram,
423*48cf7e01SChen Wang  * from top to bottom, from upstream to downstream. Read TRM for details.
424*48cf7e01SChen Wang  */
425*48cf7e01SChen Wang 
426*48cf7e01SChen Wang /* updated during probe/registration */
427*48cf7e01SChen Wang static const struct clk_hw *clk_gate_ddr01_div0[] = { NULL };
428*48cf7e01SChen Wang static const struct clk_hw *clk_gate_ddr01_div1[] = { NULL };
429*48cf7e01SChen Wang static const struct clk_hw *clk_gate_ddr23_div0[] = { NULL };
430*48cf7e01SChen Wang static const struct clk_hw *clk_gate_ddr23_div1[] = { NULL };
431*48cf7e01SChen Wang static const struct clk_hw *clk_gate_rp_cpu_normal_div0[] = { NULL };
432*48cf7e01SChen Wang static const struct clk_hw *clk_gate_rp_cpu_normal_div1[] = { NULL };
433*48cf7e01SChen Wang static const struct clk_hw *clk_gate_axi_ddr_div0[] = { NULL };
434*48cf7e01SChen Wang static const struct clk_hw *clk_gate_axi_ddr_div1[] = { NULL };
435*48cf7e01SChen Wang 
436*48cf7e01SChen Wang static const struct sg2042_gate_clock sg2042_gate_clks_level_1[] = {
437*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "dpll0",
438*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
439*48cf7e01SChen Wang 		       R_CLKDIVREG27, 4),
440*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "fpll",
441*48cf7e01SChen Wang 		       CLK_IS_CRITICAL,
442*48cf7e01SChen Wang 		       R_CLKDIVREG28, 4),
443*48cf7e01SChen Wang 
444*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "dpll1",
445*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
446*48cf7e01SChen Wang 		       R_CLKDIVREG29, 4),
447*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "fpll",
448*48cf7e01SChen Wang 		       CLK_IS_CRITICAL,
449*48cf7e01SChen Wang 		       R_CLKDIVREG30, 4),
450*48cf7e01SChen Wang 
451*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_RP_CPU_NORMAL_DIV0,
452*48cf7e01SChen Wang 		       "clk_gate_rp_cpu_normal_div0", "mpll",
453*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
454*48cf7e01SChen Wang 		       R_CLKDIVREG0, 4),
455*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_RP_CPU_NORMAL_DIV1,
456*48cf7e01SChen Wang 		       "clk_gate_rp_cpu_normal_div1", "fpll",
457*48cf7e01SChen Wang 		       CLK_IS_CRITICAL,
458*48cf7e01SChen Wang 		       R_CLKDIVREG1, 4),
459*48cf7e01SChen Wang 
460*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div0", "mpll",
461*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
462*48cf7e01SChen Wang 		       R_CLKDIVREG25, 4),
463*48cf7e01SChen Wang 	SG2042_GATE_FW(GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div1", "fpll",
464*48cf7e01SChen Wang 		       CLK_IS_CRITICAL,
465*48cf7e01SChen Wang 		       R_CLKDIVREG26, 4),
466*48cf7e01SChen Wang };
467*48cf7e01SChen Wang 
468*48cf7e01SChen Wang #define DEF_DIVFLAG (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO)
469*48cf7e01SChen Wang 
470*48cf7e01SChen Wang static struct sg2042_divider_clock sg2042_div_clks_level_1[] = {
471*48cf7e01SChen Wang 	SG2042_DIV_HWS_RO(DIV_CLK_DPLL0_DDR01_0,
472*48cf7e01SChen Wang 			  "clk_div_ddr01_0", clk_gate_ddr01_div0,
473*48cf7e01SChen Wang 			  R_CLKDIVREG27, 16, 5, DEF_DIVFLAG, 1),
474*48cf7e01SChen Wang 	SG2042_DIV_HWS_RO(DIV_CLK_FPLL_DDR01_1,
475*48cf7e01SChen Wang 			  "clk_div_ddr01_1", clk_gate_ddr01_div1,
476*48cf7e01SChen Wang 			  R_CLKDIVREG28, 16, 5, DEF_DIVFLAG, 1),
477*48cf7e01SChen Wang 
478*48cf7e01SChen Wang 	SG2042_DIV_HWS_RO(DIV_CLK_DPLL1_DDR23_0,
479*48cf7e01SChen Wang 			  "clk_div_ddr23_0", clk_gate_ddr23_div0,
480*48cf7e01SChen Wang 			  R_CLKDIVREG29, 16, 5, DEF_DIVFLAG, 1),
481*48cf7e01SChen Wang 	SG2042_DIV_HWS_RO(DIV_CLK_FPLL_DDR23_1,
482*48cf7e01SChen Wang 			  "clk_div_ddr23_1", clk_gate_ddr23_div1,
483*48cf7e01SChen Wang 			  R_CLKDIVREG30, 16, 5, DEF_DIVFLAG, 1),
484*48cf7e01SChen Wang 
485*48cf7e01SChen Wang 	SG2042_DIV_HWS(DIV_CLK_MPLL_RP_CPU_NORMAL_0,
486*48cf7e01SChen Wang 		       "clk_div_rp_cpu_normal_0", clk_gate_rp_cpu_normal_div0,
487*48cf7e01SChen Wang 		       R_CLKDIVREG0, 16, 5, DEF_DIVFLAG, 1),
488*48cf7e01SChen Wang 	SG2042_DIV_HWS(DIV_CLK_FPLL_RP_CPU_NORMAL_1,
489*48cf7e01SChen Wang 		       "clk_div_rp_cpu_normal_1", clk_gate_rp_cpu_normal_div1,
490*48cf7e01SChen Wang 		       R_CLKDIVREG1, 16, 5, DEF_DIVFLAG, 1),
491*48cf7e01SChen Wang 
492*48cf7e01SChen Wang 	SG2042_DIV_HWS(DIV_CLK_MPLL_AXI_DDR_0,
493*48cf7e01SChen Wang 		       "clk_div_axi_ddr_0", clk_gate_axi_ddr_div0,
494*48cf7e01SChen Wang 		       R_CLKDIVREG25, 16, 5, DEF_DIVFLAG, 2),
495*48cf7e01SChen Wang 	SG2042_DIV_HWS(DIV_CLK_FPLL_AXI_DDR_1,
496*48cf7e01SChen Wang 		       "clk_div_axi_ddr_1", clk_gate_axi_ddr_div1,
497*48cf7e01SChen Wang 		       R_CLKDIVREG26, 16, 5, DEF_DIVFLAG, 1),
498*48cf7e01SChen Wang };
499*48cf7e01SChen Wang 
500*48cf7e01SChen Wang /*
501*48cf7e01SChen Wang  * Note: regarding names for mux clock, "0/1" or "div0/div1" means the
502*48cf7e01SChen Wang  * first/second parent input source, not the register value.
503*48cf7e01SChen Wang  * For example:
504*48cf7e01SChen Wang  * "clk_div_ddr01_0" is the name of Clock divider 0 control of DDR01, and
505*48cf7e01SChen Wang  * "clk_gate_ddr01_div0" is the gate clock in front of the "clk_div_ddr01_0",
506*48cf7e01SChen Wang  * they are both controlled by register CLKDIVREG27;
507*48cf7e01SChen Wang  * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
508*48cf7e01SChen Wang  * "clk_gate_ddr01_div1" is the gate clock in front of the "clk_div_ddr01_1",
509*48cf7e01SChen Wang  * they are both controlled by register CLKDIVREG28;
510*48cf7e01SChen Wang  * While for register value of mux selection, use Clock Select for DDR01’s clock
511*48cf7e01SChen Wang  * as example, see CLKSELREG0, bit[2].
512*48cf7e01SChen Wang  * 1: Select in_dpll0_clk as clock source, correspondng to the parent input
513*48cf7e01SChen Wang  *    source from "clk_div_ddr01_0".
514*48cf7e01SChen Wang  * 0: Select in_fpll_clk as clock source, corresponding to the parent input
515*48cf7e01SChen Wang  *    source from "clk_div_ddr01_1".
516*48cf7e01SChen Wang  * So we need a table to define the array of register values corresponding to
517*48cf7e01SChen Wang  * the parent index and tell CCF about this when registering mux clock.
518*48cf7e01SChen Wang  */
519*48cf7e01SChen Wang static const u32 sg2042_mux_table[] = {1, 0};
520*48cf7e01SChen Wang 
521*48cf7e01SChen Wang /* Aliases just for easy reading */
522*48cf7e01SChen Wang #define clk_div_ddr01_0		(&sg2042_div_clks_level_1[0].hw)
523*48cf7e01SChen Wang #define clk_div_ddr01_1		(&sg2042_div_clks_level_1[1].hw)
524*48cf7e01SChen Wang #define clk_div_ddr23_0		(&sg2042_div_clks_level_1[2].hw)
525*48cf7e01SChen Wang #define clk_div_ddr23_1		(&sg2042_div_clks_level_1[3].hw)
526*48cf7e01SChen Wang #define clk_div_rp_cpu_normal_0	(&sg2042_div_clks_level_1[4].hw)
527*48cf7e01SChen Wang #define clk_div_rp_cpu_normal_1	(&sg2042_div_clks_level_1[5].hw)
528*48cf7e01SChen Wang #define clk_div_axi_ddr_0	(&sg2042_div_clks_level_1[6].hw)
529*48cf7e01SChen Wang #define clk_div_axi_ddr_1	(&sg2042_div_clks_level_1[7].hw)
530*48cf7e01SChen Wang 
531*48cf7e01SChen Wang static const struct clk_hw *clk_mux_ddr01_p[] = {
532*48cf7e01SChen Wang 	clk_div_ddr01_0,
533*48cf7e01SChen Wang 	clk_div_ddr01_1,
534*48cf7e01SChen Wang };
535*48cf7e01SChen Wang 
536*48cf7e01SChen Wang static const struct clk_hw *clk_mux_ddr23_p[] = {
537*48cf7e01SChen Wang 	clk_div_ddr23_0,
538*48cf7e01SChen Wang 	clk_div_ddr23_1,
539*48cf7e01SChen Wang };
540*48cf7e01SChen Wang 
541*48cf7e01SChen Wang static const struct clk_hw *clk_mux_rp_cpu_normal_p[] = {
542*48cf7e01SChen Wang 	clk_div_rp_cpu_normal_0,
543*48cf7e01SChen Wang 	clk_div_rp_cpu_normal_1,
544*48cf7e01SChen Wang };
545*48cf7e01SChen Wang 
546*48cf7e01SChen Wang static const struct clk_hw *clk_mux_axi_ddr_p[] = {
547*48cf7e01SChen Wang 	clk_div_axi_ddr_0,
548*48cf7e01SChen Wang 	clk_div_axi_ddr_1,
549*48cf7e01SChen Wang };
550*48cf7e01SChen Wang 
551*48cf7e01SChen Wang /* Mux clocks to be updated during probe/registration */
552*48cf7e01SChen Wang static const struct clk_hw *clk_mux_ddr01[] = { NULL };
553*48cf7e01SChen Wang static const struct clk_hw *clk_mux_ddr23[] = { NULL };
554*48cf7e01SChen Wang static const struct clk_hw *clk_mux_rp_cpu_normal[] = { NULL };
555*48cf7e01SChen Wang static const struct clk_hw *clk_mux_axi_ddr[] = { NULL };
556*48cf7e01SChen Wang 
557*48cf7e01SChen Wang static struct sg2042_mux_clock sg2042_mux_clks[] = {
558*48cf7e01SChen Wang 	SG2042_MUX(MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p,
559*48cf7e01SChen Wang 		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
560*48cf7e01SChen Wang 		   R_CLKSELREG0, 2, 1),
561*48cf7e01SChen Wang 	SG2042_MUX(MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p,
562*48cf7e01SChen Wang 		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
563*48cf7e01SChen Wang 		   R_CLKSELREG0, 3, 1),
564*48cf7e01SChen Wang 	SG2042_MUX(MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p,
565*48cf7e01SChen Wang 		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
566*48cf7e01SChen Wang 		   R_CLKSELREG0, 0, 1),
567*48cf7e01SChen Wang 	SG2042_MUX(MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p,
568*48cf7e01SChen Wang 		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
569*48cf7e01SChen Wang 		   R_CLKSELREG0, 1, 1),
570*48cf7e01SChen Wang };
571*48cf7e01SChen Wang 
572*48cf7e01SChen Wang /* Aliases just for easy reading */
573*48cf7e01SChen Wang #define clk_div_top_rp_cmn_div2	(&sg2042_div_clks_level_2[0].hw)
574*48cf7e01SChen Wang #define clk_div_50m_a53		(&sg2042_div_clks_level_2[1].hw)
575*48cf7e01SChen Wang #define clk_div_timer1		(&sg2042_div_clks_level_2[2].hw)
576*48cf7e01SChen Wang #define clk_div_timer2		(&sg2042_div_clks_level_2[3].hw)
577*48cf7e01SChen Wang #define clk_div_timer3		(&sg2042_div_clks_level_2[4].hw)
578*48cf7e01SChen Wang #define clk_div_timer4		(&sg2042_div_clks_level_2[5].hw)
579*48cf7e01SChen Wang #define clk_div_timer5		(&sg2042_div_clks_level_2[6].hw)
580*48cf7e01SChen Wang #define clk_div_timer6		(&sg2042_div_clks_level_2[7].hw)
581*48cf7e01SChen Wang #define clk_div_timer7		(&sg2042_div_clks_level_2[8].hw)
582*48cf7e01SChen Wang #define clk_div_timer8		(&sg2042_div_clks_level_2[9].hw)
583*48cf7e01SChen Wang #define clk_div_uart_500m	(&sg2042_div_clks_level_2[10].hw)
584*48cf7e01SChen Wang #define clk_div_ahb_lpc		(&sg2042_div_clks_level_2[11].hw)
585*48cf7e01SChen Wang #define clk_div_efuse		(&sg2042_div_clks_level_2[12].hw)
586*48cf7e01SChen Wang #define clk_div_tx_eth0		(&sg2042_div_clks_level_2[13].hw)
587*48cf7e01SChen Wang #define clk_div_ptp_ref_i_eth0	(&sg2042_div_clks_level_2[14].hw)
588*48cf7e01SChen Wang #define clk_div_ref_eth0	(&sg2042_div_clks_level_2[15].hw)
589*48cf7e01SChen Wang #define clk_div_emmc		(&sg2042_div_clks_level_2[16].hw)
590*48cf7e01SChen Wang #define clk_div_sd		(&sg2042_div_clks_level_2[17].hw)
591*48cf7e01SChen Wang #define clk_div_top_axi0	(&sg2042_div_clks_level_2[18].hw)
592*48cf7e01SChen Wang #define clk_div_100k_emmc	(&sg2042_div_clks_level_2[19].hw)
593*48cf7e01SChen Wang #define clk_div_100k_sd		(&sg2042_div_clks_level_2[20].hw)
594*48cf7e01SChen Wang #define clk_div_gpio_db		(&sg2042_div_clks_level_2[21].hw)
595*48cf7e01SChen Wang #define clk_div_top_axi_hsperi	(&sg2042_div_clks_level_2[22].hw)
596*48cf7e01SChen Wang 
597*48cf7e01SChen Wang static struct sg2042_divider_clock sg2042_div_clks_level_2[] = {
598*48cf7e01SChen Wang 	SG2042_DIV_HWS(DIV_CLK_FPLL_TOP_RP_CMN_DIV2,
599*48cf7e01SChen Wang 		       "clk_div_top_rp_cmn_div2", clk_mux_rp_cpu_normal,
600*48cf7e01SChen Wang 		       R_CLKDIVREG3, 16, 16, DEF_DIVFLAG, 2),
601*48cf7e01SChen Wang 
602*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll",
603*48cf7e01SChen Wang 		      R_CLKDIVREG2, 16, 8, DEF_DIVFLAG, 20),
604*48cf7e01SChen Wang 	/* downstream of div_50m_a53 */
605*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", clk_div_50m_a53,
606*48cf7e01SChen Wang 		      R_CLKDIVREG6, 16, 16, DEF_DIVFLAG, 1),
607*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", clk_div_50m_a53,
608*48cf7e01SChen Wang 		      R_CLKDIVREG7, 16, 16, DEF_DIVFLAG, 1),
609*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", clk_div_50m_a53,
610*48cf7e01SChen Wang 		      R_CLKDIVREG8, 16, 16, DEF_DIVFLAG, 1),
611*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", clk_div_50m_a53,
612*48cf7e01SChen Wang 		      R_CLKDIVREG9, 16, 16, DEF_DIVFLAG, 1),
613*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", clk_div_50m_a53,
614*48cf7e01SChen Wang 		      R_CLKDIVREG10, 16, 16, DEF_DIVFLAG, 1),
615*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", clk_div_50m_a53,
616*48cf7e01SChen Wang 		      R_CLKDIVREG11, 16, 16, DEF_DIVFLAG, 1),
617*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", clk_div_50m_a53,
618*48cf7e01SChen Wang 		      R_CLKDIVREG12, 16, 16, DEF_DIVFLAG, 1),
619*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", clk_div_50m_a53,
620*48cf7e01SChen Wang 		      R_CLKDIVREG13, 16, 16, DEF_DIVFLAG, 1),
621*48cf7e01SChen Wang 
622*48cf7e01SChen Wang 	/*
623*48cf7e01SChen Wang 	 * Set clk_div_uart_500m as RO, because the width of CLKDIVREG4 is too
624*48cf7e01SChen Wang 	 * narrow for us to produce 115200. Use UART internal divider directly.
625*48cf7e01SChen Wang 	 */
626*48cf7e01SChen Wang 	SG2042_DIV_FW_RO(DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll",
627*48cf7e01SChen Wang 			 R_CLKDIVREG4, 16, 7, DEF_DIVFLAG, 2),
628*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll",
629*48cf7e01SChen Wang 		      R_CLKDIVREG5, 16, 16, DEF_DIVFLAG, 5),
630*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll",
631*48cf7e01SChen Wang 		      R_CLKDIVREG14, 16, 7, DEF_DIVFLAG, 40),
632*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll",
633*48cf7e01SChen Wang 		      R_CLKDIVREG16, 16, 11, DEF_DIVFLAG, 8),
634*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_PTP_REF_I_ETH0,
635*48cf7e01SChen Wang 		      "clk_div_ptp_ref_i_eth0", "fpll",
636*48cf7e01SChen Wang 		      R_CLKDIVREG17, 16, 8, DEF_DIVFLAG, 20),
637*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll",
638*48cf7e01SChen Wang 		      R_CLKDIVREG18, 16, 8, DEF_DIVFLAG, 40),
639*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll",
640*48cf7e01SChen Wang 		      R_CLKDIVREG19, 16, 5, DEF_DIVFLAG, 10),
641*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_SD, "clk_div_sd", "fpll",
642*48cf7e01SChen Wang 		      R_CLKDIVREG21, 16, 5, DEF_DIVFLAG, 10),
643*48cf7e01SChen Wang 
644*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll",
645*48cf7e01SChen Wang 		      R_CLKDIVREG23, 16, 5, DEF_DIVFLAG, 10),
646*48cf7e01SChen Wang 	/* downstream of div_top_axi0 */
647*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", clk_div_top_axi0,
648*48cf7e01SChen Wang 		      R_CLKDIVREG20, 16, 16, DEF_DIVFLAG, 1000),
649*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", clk_div_top_axi0,
650*48cf7e01SChen Wang 		      R_CLKDIVREG22, 16, 16, DEF_DIVFLAG, 1000),
651*48cf7e01SChen Wang 	SG2042_DIV_HW(DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", clk_div_top_axi0,
652*48cf7e01SChen Wang 		      R_CLKDIVREG15, 16, 16, DEF_DIVFLAG, 1000),
653*48cf7e01SChen Wang 
654*48cf7e01SChen Wang 	SG2042_DIV_FW(DIV_CLK_FPLL_TOP_AXI_HSPERI,
655*48cf7e01SChen Wang 		      "clk_div_top_axi_hsperi", "fpll",
656*48cf7e01SChen Wang 		      R_CLKDIVREG24, 16, 5, DEF_DIVFLAG, 4),
657*48cf7e01SChen Wang };
658*48cf7e01SChen Wang 
659*48cf7e01SChen Wang /* Gate clocks to be updated during probe/registration */
660*48cf7e01SChen Wang static const struct clk_hw *clk_gate_rp_cpu_normal[] = { NULL };
661*48cf7e01SChen Wang static const struct clk_hw *clk_gate_top_rp_cmn_div2[] = { NULL };
662*48cf7e01SChen Wang 
663*48cf7e01SChen Wang static const struct sg2042_gate_clock sg2042_gate_clks_level_2[] = {
664*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_DDR01, "clk_gate_ddr01", clk_mux_ddr01,
665*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
666*48cf7e01SChen Wang 			R_CLKENREG1, 14),
667*48cf7e01SChen Wang 
668*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_DDR23, "clk_gate_ddr23", clk_mux_ddr23,
669*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
670*48cf7e01SChen Wang 			R_CLKENREG1, 15),
671*48cf7e01SChen Wang 
672*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_RP_CPU_NORMAL,
673*48cf7e01SChen Wang 			"clk_gate_rp_cpu_normal", clk_mux_rp_cpu_normal,
674*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
675*48cf7e01SChen Wang 			R_CLKENREG0, 0),
676*48cf7e01SChen Wang 
677*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", clk_mux_axi_ddr,
678*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
679*48cf7e01SChen Wang 			R_CLKENREG1, 13),
680*48cf7e01SChen Wang 
681*48cf7e01SChen Wang 	/* upon are gate clocks directly downstream of muxes */
682*48cf7e01SChen Wang 
683*48cf7e01SChen Wang 	/* downstream of clk_div_top_rp_cmn_div2 */
684*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TOP_RP_CMN_DIV2,
685*48cf7e01SChen Wang 		       "clk_gate_top_rp_cmn_div2", clk_div_top_rp_cmn_div2,
686*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 2),
687*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_HSDMA, "clk_gate_hsdma", clk_gate_top_rp_cmn_div2,
688*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT, R_CLKENREG1, 10),
689*48cf7e01SChen Wang 
690*48cf7e01SChen Wang 	/*
691*48cf7e01SChen Wang 	 * downstream of clk_gate_rp_cpu_normal
692*48cf7e01SChen Wang 	 *
693*48cf7e01SChen Wang 	 * FIXME: there should be one 1/2 DIV between clk_gate_rp_cpu_normal
694*48cf7e01SChen Wang 	 * and clk_gate_axi_pcie0/clk_gate_axi_pcie1.
695*48cf7e01SChen Wang 	 * But the 1/2 DIV is fixed and no configurable register exported, so
696*48cf7e01SChen Wang 	 * when reading from these two clocks, the rate value are still the
697*48cf7e01SChen Wang 	 * same as that of clk_gate_rp_cpu_normal, it's not correct.
698*48cf7e01SChen Wang 	 * This just affects the value read.
699*48cf7e01SChen Wang 	 */
700*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_AXI_PCIE0,
701*48cf7e01SChen Wang 			"clk_gate_axi_pcie0", clk_gate_rp_cpu_normal,
702*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 8),
703*48cf7e01SChen Wang 	SG2042_GATE_HWS(GATE_CLK_AXI_PCIE1,
704*48cf7e01SChen Wang 			"clk_gate_axi_pcie1", clk_gate_rp_cpu_normal,
705*48cf7e01SChen Wang 			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 9),
706*48cf7e01SChen Wang 
707*48cf7e01SChen Wang 	/* downstream of div_50m_a53 */
708*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_A53_50M, "clk_gate_a53_50m", clk_div_50m_a53,
709*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 1),
710*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER1, "clk_gate_timer1", clk_div_timer1,
711*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 12),
712*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER2, "clk_gate_timer2", clk_div_timer2,
713*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 13),
714*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER3, "clk_gate_timer3", clk_div_timer3,
715*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 14),
716*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER4, "clk_gate_timer4", clk_div_timer4,
717*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 15),
718*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER5, "clk_gate_timer5", clk_div_timer5,
719*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 16),
720*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER6, "clk_gate_timer6", clk_div_timer6,
721*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 17),
722*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER7, "clk_gate_timer7", clk_div_timer7,
723*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 18),
724*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TIMER8, "clk_gate_timer8", clk_div_timer8,
725*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 19),
726*48cf7e01SChen Wang 
727*48cf7e01SChen Wang 	/* gate clocks downstream from div clocks one-to-one */
728*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_UART_500M, "clk_gate_uart_500m", clk_div_uart_500m,
729*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 4),
730*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", clk_div_ahb_lpc,
731*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 7),
732*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_EFUSE, "clk_gate_efuse", clk_div_efuse,
733*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 20),
734*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", clk_div_tx_eth0,
735*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 30),
736*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_PTP_REF_I_ETH0,
737*48cf7e01SChen Wang 		       "clk_gate_ptp_ref_i_eth0", clk_div_ptp_ref_i_eth0,
738*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 0),
739*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", clk_div_ref_eth0,
740*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 1),
741*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_EMMC_100M, "clk_gate_emmc", clk_div_emmc,
742*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 3),
743*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_SD_100M, "clk_gate_sd", clk_div_sd,
744*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 6),
745*48cf7e01SChen Wang 
746*48cf7e01SChen Wang 	/* downstream of clk_div_top_axi0 */
747*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", clk_div_top_axi0,
748*48cf7e01SChen Wang 		       0, R_CLKENREG0, 8),
749*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AHB_SF, "clk_gate_ahb_sf", clk_div_top_axi0,
750*48cf7e01SChen Wang 		       0, R_CLKENREG0, 9),
751*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", clk_div_top_axi0,
752*48cf7e01SChen Wang 		       CLK_IGNORE_UNUSED, R_CLKENREG0, 10),
753*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_TIMER, "clk_gate_apb_timer", clk_div_top_axi0,
754*48cf7e01SChen Wang 		       CLK_IGNORE_UNUSED, R_CLKENREG0, 11),
755*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", clk_div_top_axi0,
756*48cf7e01SChen Wang 		       0, R_CLKENREG0, 21),
757*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", clk_div_top_axi0,
758*48cf7e01SChen Wang 		       0, R_CLKENREG0, 22),
759*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_GPIO_INTR,
760*48cf7e01SChen Wang 		       "clk_gate_apb_gpio_intr", clk_div_top_axi0,
761*48cf7e01SChen Wang 		       CLK_IS_CRITICAL, R_CLKENREG0, 23),
762*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_I2C, "clk_gate_apb_i2c", clk_div_top_axi0,
763*48cf7e01SChen Wang 		       0, R_CLKENREG0, 26),
764*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_WDT, "clk_gate_apb_wdt", clk_div_top_axi0,
765*48cf7e01SChen Wang 		       0, R_CLKENREG0, 27),
766*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_PWM, "clk_gate_apb_pwm", clk_div_top_axi0,
767*48cf7e01SChen Wang 		       0, R_CLKENREG0, 28),
768*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_RTC, "clk_gate_apb_rtc", clk_div_top_axi0,
769*48cf7e01SChen Wang 		       0, R_CLKENREG0, 29),
770*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", clk_div_top_axi0,
771*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
772*48cf7e01SChen Wang 		       R_CLKENREG1, 11),
773*48cf7e01SChen Wang 	/* downstream of DIV clocks which are sourced from clk_div_top_axi0 */
774*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_GPIO_DB, "clk_gate_gpio_db", clk_div_gpio_db,
775*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 24),
776*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", clk_div_100k_emmc,
777*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 4),
778*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_100K_SD, "clk_gate_100k_sd", clk_div_100k_sd,
779*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 7),
780*48cf7e01SChen Wang 
781*48cf7e01SChen Wang 	/* downstream of clk_div_top_axi_hsperi */
782*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_SYSDMA_AXI,
783*48cf7e01SChen Wang 		       "clk_gate_sysdma_axi", clk_div_top_axi_hsperi,
784*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 3),
785*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_UART,
786*48cf7e01SChen Wang 		       "clk_gate_apb_uart", clk_div_top_axi_hsperi,
787*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 5),
788*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AXI_DBG_I2C,
789*48cf7e01SChen Wang 		       "clk_gate_axi_dbg_i2c", clk_div_top_axi_hsperi,
790*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 6),
791*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_APB_SPI,
792*48cf7e01SChen Wang 		       "clk_gate_apb_spi", clk_div_top_axi_hsperi,
793*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 25),
794*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AXI_ETH0,
795*48cf7e01SChen Wang 		       "clk_gate_axi_eth0", clk_div_top_axi_hsperi,
796*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG0, 31),
797*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AXI_EMMC,
798*48cf7e01SChen Wang 		       "clk_gate_axi_emmc", clk_div_top_axi_hsperi,
799*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 2),
800*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_AXI_SD,
801*48cf7e01SChen Wang 		       "clk_gate_axi_sd", clk_div_top_axi_hsperi,
802*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT, R_CLKENREG1, 5),
803*48cf7e01SChen Wang 	SG2042_GATE_HW(GATE_CLK_TOP_AXI_HSPERI,
804*48cf7e01SChen Wang 		       "clk_gate_top_axi_hsperi", clk_div_top_axi_hsperi,
805*48cf7e01SChen Wang 		       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
806*48cf7e01SChen Wang 		       R_CLKENREG1, 12),
807*48cf7e01SChen Wang };
808*48cf7e01SChen Wang 
809*48cf7e01SChen Wang static DEFINE_SPINLOCK(sg2042_clk_lock);
810*48cf7e01SChen Wang 
sg2042_clk_register_divs(struct device * dev,struct sg2042_clk_data * clk_data,struct sg2042_divider_clock div_clks[],int num_div_clks)811*48cf7e01SChen Wang static int sg2042_clk_register_divs(struct device *dev,
812*48cf7e01SChen Wang 				    struct sg2042_clk_data *clk_data,
813*48cf7e01SChen Wang 				    struct sg2042_divider_clock div_clks[],
814*48cf7e01SChen Wang 				    int num_div_clks)
815*48cf7e01SChen Wang {
816*48cf7e01SChen Wang 	struct sg2042_divider_clock *div;
817*48cf7e01SChen Wang 	struct clk_hw *hw;
818*48cf7e01SChen Wang 	int i, ret = 0;
819*48cf7e01SChen Wang 
820*48cf7e01SChen Wang 	for (i = 0; i < num_div_clks; i++) {
821*48cf7e01SChen Wang 		div = &div_clks[i];
822*48cf7e01SChen Wang 
823*48cf7e01SChen Wang 		if (div->div_flags & CLK_DIVIDER_HIWORD_MASK) {
824*48cf7e01SChen Wang 			if (div->width + div->shift > 16) {
825*48cf7e01SChen Wang 				pr_warn("divider value exceeds LOWORD field\n");
826*48cf7e01SChen Wang 				ret = -EINVAL;
827*48cf7e01SChen Wang 				break;
828*48cf7e01SChen Wang 			}
829*48cf7e01SChen Wang 		}
830*48cf7e01SChen Wang 
831*48cf7e01SChen Wang 		div->reg = clk_data->iobase + div->offset_ctrl;
832*48cf7e01SChen Wang 		div->lock = &sg2042_clk_lock;
833*48cf7e01SChen Wang 
834*48cf7e01SChen Wang 		hw = &div->hw;
835*48cf7e01SChen Wang 		ret = devm_clk_hw_register(dev, hw);
836*48cf7e01SChen Wang 		if (ret) {
837*48cf7e01SChen Wang 			pr_err("failed to register clock %s\n", div->hw.init->name);
838*48cf7e01SChen Wang 			break;
839*48cf7e01SChen Wang 		}
840*48cf7e01SChen Wang 
841*48cf7e01SChen Wang 		clk_data->onecell_data.hws[div->id] = hw;
842*48cf7e01SChen Wang 	}
843*48cf7e01SChen Wang 
844*48cf7e01SChen Wang 	return ret;
845*48cf7e01SChen Wang }
846*48cf7e01SChen Wang 
sg2042_clk_register_gates(struct device * dev,struct sg2042_clk_data * clk_data,const struct sg2042_gate_clock gate_clks[],int num_gate_clks)847*48cf7e01SChen Wang static int sg2042_clk_register_gates(struct device *dev,
848*48cf7e01SChen Wang 				     struct sg2042_clk_data *clk_data,
849*48cf7e01SChen Wang 				     const struct sg2042_gate_clock gate_clks[],
850*48cf7e01SChen Wang 				     int num_gate_clks)
851*48cf7e01SChen Wang {
852*48cf7e01SChen Wang 	const struct sg2042_gate_clock *gate;
853*48cf7e01SChen Wang 	struct clk_hw *hw;
854*48cf7e01SChen Wang 	int i, ret = 0;
855*48cf7e01SChen Wang 
856*48cf7e01SChen Wang 	for (i = 0; i < num_gate_clks; i++) {
857*48cf7e01SChen Wang 		gate = &gate_clks[i];
858*48cf7e01SChen Wang 		hw = __devm_clk_hw_register_gate
859*48cf7e01SChen Wang 			(dev,
860*48cf7e01SChen Wang 			 NULL,
861*48cf7e01SChen Wang 			 gate->hw.init->name,
862*48cf7e01SChen Wang 			 NULL,
863*48cf7e01SChen Wang 			 gate->hw.init->parent_hws[0],
864*48cf7e01SChen Wang 			 NULL,
865*48cf7e01SChen Wang 			 gate->hw.init->flags,
866*48cf7e01SChen Wang 			 clk_data->iobase + gate->offset_enable,
867*48cf7e01SChen Wang 			 gate->bit_idx,
868*48cf7e01SChen Wang 			 0,
869*48cf7e01SChen Wang 			 &sg2042_clk_lock);
870*48cf7e01SChen Wang 		if (IS_ERR(hw)) {
871*48cf7e01SChen Wang 			pr_err("failed to register clock %s\n", gate->hw.init->name);
872*48cf7e01SChen Wang 			ret = PTR_ERR(hw);
873*48cf7e01SChen Wang 			break;
874*48cf7e01SChen Wang 		}
875*48cf7e01SChen Wang 
876*48cf7e01SChen Wang 		clk_data->onecell_data.hws[gate->id] = hw;
877*48cf7e01SChen Wang 
878*48cf7e01SChen Wang 		/* Updated some clocks which take the role of parent */
879*48cf7e01SChen Wang 		switch (gate->id) {
880*48cf7e01SChen Wang 		case GATE_CLK_RP_CPU_NORMAL:
881*48cf7e01SChen Wang 			*clk_gate_rp_cpu_normal = hw;
882*48cf7e01SChen Wang 			break;
883*48cf7e01SChen Wang 		case GATE_CLK_TOP_RP_CMN_DIV2:
884*48cf7e01SChen Wang 			*clk_gate_top_rp_cmn_div2 = hw;
885*48cf7e01SChen Wang 			break;
886*48cf7e01SChen Wang 		}
887*48cf7e01SChen Wang 	}
888*48cf7e01SChen Wang 
889*48cf7e01SChen Wang 	return ret;
890*48cf7e01SChen Wang }
891*48cf7e01SChen Wang 
sg2042_clk_register_gates_fw(struct device * dev,struct sg2042_clk_data * clk_data,const struct sg2042_gate_clock gate_clks[],int num_gate_clks)892*48cf7e01SChen Wang static int sg2042_clk_register_gates_fw(struct device *dev,
893*48cf7e01SChen Wang 					struct sg2042_clk_data *clk_data,
894*48cf7e01SChen Wang 					const struct sg2042_gate_clock gate_clks[],
895*48cf7e01SChen Wang 					int num_gate_clks)
896*48cf7e01SChen Wang {
897*48cf7e01SChen Wang 	const struct sg2042_gate_clock *gate;
898*48cf7e01SChen Wang 	struct clk_hw *hw;
899*48cf7e01SChen Wang 	int i, ret = 0;
900*48cf7e01SChen Wang 
901*48cf7e01SChen Wang 	for (i = 0; i < num_gate_clks; i++) {
902*48cf7e01SChen Wang 		gate = &gate_clks[i];
903*48cf7e01SChen Wang 		hw = devm_clk_hw_register_gate_parent_data
904*48cf7e01SChen Wang 			(dev,
905*48cf7e01SChen Wang 			 gate->hw.init->name,
906*48cf7e01SChen Wang 			 gate->hw.init->parent_data,
907*48cf7e01SChen Wang 			 gate->hw.init->flags,
908*48cf7e01SChen Wang 			 clk_data->iobase + gate->offset_enable,
909*48cf7e01SChen Wang 			 gate->bit_idx,
910*48cf7e01SChen Wang 			 0,
911*48cf7e01SChen Wang 			 &sg2042_clk_lock);
912*48cf7e01SChen Wang 		if (IS_ERR(hw)) {
913*48cf7e01SChen Wang 			pr_err("failed to register clock %s\n", gate->hw.init->name);
914*48cf7e01SChen Wang 			ret = PTR_ERR(hw);
915*48cf7e01SChen Wang 			break;
916*48cf7e01SChen Wang 		}
917*48cf7e01SChen Wang 
918*48cf7e01SChen Wang 		clk_data->onecell_data.hws[gate->id] = hw;
919*48cf7e01SChen Wang 
920*48cf7e01SChen Wang 		/* Updated some clocks which take the role of parent */
921*48cf7e01SChen Wang 		switch (gate->id) {
922*48cf7e01SChen Wang 		case GATE_CLK_DDR01_DIV0:
923*48cf7e01SChen Wang 			*clk_gate_ddr01_div0 = hw;
924*48cf7e01SChen Wang 			break;
925*48cf7e01SChen Wang 		case GATE_CLK_DDR01_DIV1:
926*48cf7e01SChen Wang 			*clk_gate_ddr01_div1 = hw;
927*48cf7e01SChen Wang 			break;
928*48cf7e01SChen Wang 		case GATE_CLK_DDR23_DIV0:
929*48cf7e01SChen Wang 			*clk_gate_ddr23_div0 = hw;
930*48cf7e01SChen Wang 			break;
931*48cf7e01SChen Wang 		case GATE_CLK_DDR23_DIV1:
932*48cf7e01SChen Wang 			*clk_gate_ddr23_div1 = hw;
933*48cf7e01SChen Wang 			break;
934*48cf7e01SChen Wang 		case GATE_CLK_RP_CPU_NORMAL_DIV0:
935*48cf7e01SChen Wang 			*clk_gate_rp_cpu_normal_div0 = hw;
936*48cf7e01SChen Wang 			break;
937*48cf7e01SChen Wang 		case GATE_CLK_RP_CPU_NORMAL_DIV1:
938*48cf7e01SChen Wang 			*clk_gate_rp_cpu_normal_div1 = hw;
939*48cf7e01SChen Wang 			break;
940*48cf7e01SChen Wang 		case GATE_CLK_AXI_DDR_DIV0:
941*48cf7e01SChen Wang 			*clk_gate_axi_ddr_div0 = hw;
942*48cf7e01SChen Wang 			break;
943*48cf7e01SChen Wang 		case GATE_CLK_AXI_DDR_DIV1:
944*48cf7e01SChen Wang 			*clk_gate_axi_ddr_div1 = hw;
945*48cf7e01SChen Wang 			break;
946*48cf7e01SChen Wang 		}
947*48cf7e01SChen Wang 	}
948*48cf7e01SChen Wang 
949*48cf7e01SChen Wang 	return ret;
950*48cf7e01SChen Wang }
951*48cf7e01SChen Wang 
sg2042_mux_notifier_cb(struct notifier_block * nb,unsigned long event,void * data)952*48cf7e01SChen Wang static int sg2042_mux_notifier_cb(struct notifier_block *nb,
953*48cf7e01SChen Wang 				  unsigned long event,
954*48cf7e01SChen Wang 				  void *data)
955*48cf7e01SChen Wang {
956*48cf7e01SChen Wang 	struct sg2042_mux_clock *mux = to_sg2042_mux_nb(nb);
957*48cf7e01SChen Wang 	const struct clk_ops *ops = &clk_mux_ops;
958*48cf7e01SChen Wang 	struct clk_notifier_data *ndata = data;
959*48cf7e01SChen Wang 	struct clk_hw *hw;
960*48cf7e01SChen Wang 	int ret = 0;
961*48cf7e01SChen Wang 
962*48cf7e01SChen Wang 	hw = __clk_get_hw(ndata->clk);
963*48cf7e01SChen Wang 
964*48cf7e01SChen Wang 	/* To switch to fpll before changing rate and restore after that */
965*48cf7e01SChen Wang 	if (event == PRE_RATE_CHANGE) {
966*48cf7e01SChen Wang 		mux->original_index = ops->get_parent(hw);
967*48cf7e01SChen Wang 
968*48cf7e01SChen Wang 		/*
969*48cf7e01SChen Wang 		 * "1" is the array index of the second parent input source of
970*48cf7e01SChen Wang 		 * mux. For SG2042, it's fpll for all mux clocks.
971*48cf7e01SChen Wang 		 * "0" is the array index of the frist parent input source of
972*48cf7e01SChen Wang 		 * mux, For SG2042, it's mpll.
973*48cf7e01SChen Wang 		 * FIXME, any good idea to avoid magic number?
974*48cf7e01SChen Wang 		 */
975*48cf7e01SChen Wang 		if (mux->original_index == 0)
976*48cf7e01SChen Wang 			ret = ops->set_parent(hw, 1);
977*48cf7e01SChen Wang 	} else if (event == POST_RATE_CHANGE) {
978*48cf7e01SChen Wang 		ret = ops->set_parent(hw, mux->original_index);
979*48cf7e01SChen Wang 	}
980*48cf7e01SChen Wang 
981*48cf7e01SChen Wang 	return notifier_from_errno(ret);
982*48cf7e01SChen Wang }
983*48cf7e01SChen Wang 
sg2042_clk_register_muxs(struct device * dev,struct sg2042_clk_data * clk_data,struct sg2042_mux_clock mux_clks[],int num_mux_clks)984*48cf7e01SChen Wang static int sg2042_clk_register_muxs(struct device *dev,
985*48cf7e01SChen Wang 				    struct sg2042_clk_data *clk_data,
986*48cf7e01SChen Wang 				    struct sg2042_mux_clock mux_clks[],
987*48cf7e01SChen Wang 				    int num_mux_clks)
988*48cf7e01SChen Wang {
989*48cf7e01SChen Wang 	struct sg2042_mux_clock *mux;
990*48cf7e01SChen Wang 	struct clk_hw *hw;
991*48cf7e01SChen Wang 	int i, ret = 0;
992*48cf7e01SChen Wang 
993*48cf7e01SChen Wang 	for (i = 0; i < num_mux_clks; i++) {
994*48cf7e01SChen Wang 		mux = &mux_clks[i];
995*48cf7e01SChen Wang 
996*48cf7e01SChen Wang 		hw = __devm_clk_hw_register_mux
997*48cf7e01SChen Wang 			(dev,
998*48cf7e01SChen Wang 			 NULL,
999*48cf7e01SChen Wang 			 mux->hw.init->name,
1000*48cf7e01SChen Wang 			 mux->hw.init->num_parents,
1001*48cf7e01SChen Wang 			 NULL,
1002*48cf7e01SChen Wang 			 mux->hw.init->parent_hws,
1003*48cf7e01SChen Wang 			 NULL,
1004*48cf7e01SChen Wang 			 mux->hw.init->flags,
1005*48cf7e01SChen Wang 			 clk_data->iobase + mux->offset_select,
1006*48cf7e01SChen Wang 			 mux->shift,
1007*48cf7e01SChen Wang 			 BIT(mux->width) - 1,
1008*48cf7e01SChen Wang 			 0,
1009*48cf7e01SChen Wang 			 sg2042_mux_table,
1010*48cf7e01SChen Wang 			 &sg2042_clk_lock);
1011*48cf7e01SChen Wang 		if (IS_ERR(hw)) {
1012*48cf7e01SChen Wang 			pr_err("failed to register clock %s\n", mux->hw.init->name);
1013*48cf7e01SChen Wang 			ret = PTR_ERR(hw);
1014*48cf7e01SChen Wang 			break;
1015*48cf7e01SChen Wang 		}
1016*48cf7e01SChen Wang 
1017*48cf7e01SChen Wang 		clk_data->onecell_data.hws[mux->id] = hw;
1018*48cf7e01SChen Wang 
1019*48cf7e01SChen Wang 		/* Updated some clocks which takes the role of parent */
1020*48cf7e01SChen Wang 		switch (mux->id) {
1021*48cf7e01SChen Wang 		case MUX_CLK_DDR01:
1022*48cf7e01SChen Wang 			*clk_mux_ddr01 = hw;
1023*48cf7e01SChen Wang 			break;
1024*48cf7e01SChen Wang 		case MUX_CLK_DDR23:
1025*48cf7e01SChen Wang 			*clk_mux_ddr23 = hw;
1026*48cf7e01SChen Wang 			break;
1027*48cf7e01SChen Wang 		case MUX_CLK_RP_CPU_NORMAL:
1028*48cf7e01SChen Wang 			*clk_mux_rp_cpu_normal = hw;
1029*48cf7e01SChen Wang 			break;
1030*48cf7e01SChen Wang 		case MUX_CLK_AXI_DDR:
1031*48cf7e01SChen Wang 			*clk_mux_axi_ddr = hw;
1032*48cf7e01SChen Wang 			break;
1033*48cf7e01SChen Wang 		}
1034*48cf7e01SChen Wang 
1035*48cf7e01SChen Wang 		/*
1036*48cf7e01SChen Wang 		 * FIXME: Theoretically, we should set parent for the
1037*48cf7e01SChen Wang 		 * mux, but seems hardware has done this for us with
1038*48cf7e01SChen Wang 		 * default value, so we don't set parent again here.
1039*48cf7e01SChen Wang 		 */
1040*48cf7e01SChen Wang 
1041*48cf7e01SChen Wang 		if (!(mux->hw.init->flags & CLK_MUX_READ_ONLY)) {
1042*48cf7e01SChen Wang 			mux->clk_nb.notifier_call = sg2042_mux_notifier_cb;
1043*48cf7e01SChen Wang 			ret = devm_clk_notifier_register(dev, hw->clk, &mux->clk_nb);
1044*48cf7e01SChen Wang 			if (ret) {
1045*48cf7e01SChen Wang 				pr_err("failed to register clock notifier for %s\n",
1046*48cf7e01SChen Wang 				       mux->hw.init->name);
1047*48cf7e01SChen Wang 				break;
1048*48cf7e01SChen Wang 			}
1049*48cf7e01SChen Wang 		}
1050*48cf7e01SChen Wang 	}
1051*48cf7e01SChen Wang 
1052*48cf7e01SChen Wang 	return ret;
1053*48cf7e01SChen Wang }
1054*48cf7e01SChen Wang 
sg2042_init_clkdata(struct platform_device * pdev,int num_clks,struct sg2042_clk_data ** pp_clk_data)1055*48cf7e01SChen Wang static int sg2042_init_clkdata(struct platform_device *pdev,
1056*48cf7e01SChen Wang 			       int num_clks,
1057*48cf7e01SChen Wang 			       struct sg2042_clk_data **pp_clk_data)
1058*48cf7e01SChen Wang {
1059*48cf7e01SChen Wang 	struct sg2042_clk_data *clk_data = NULL;
1060*48cf7e01SChen Wang 
1061*48cf7e01SChen Wang 	clk_data = devm_kzalloc(&pdev->dev,
1062*48cf7e01SChen Wang 				struct_size(clk_data, onecell_data.hws, num_clks),
1063*48cf7e01SChen Wang 				GFP_KERNEL);
1064*48cf7e01SChen Wang 	if (!clk_data)
1065*48cf7e01SChen Wang 		return -ENOMEM;
1066*48cf7e01SChen Wang 
1067*48cf7e01SChen Wang 	clk_data->iobase = devm_platform_ioremap_resource(pdev, 0);
1068*48cf7e01SChen Wang 	if (WARN_ON(IS_ERR(clk_data->iobase)))
1069*48cf7e01SChen Wang 		return PTR_ERR(clk_data->iobase);
1070*48cf7e01SChen Wang 
1071*48cf7e01SChen Wang 	clk_data->onecell_data.num = num_clks;
1072*48cf7e01SChen Wang 
1073*48cf7e01SChen Wang 	*pp_clk_data = clk_data;
1074*48cf7e01SChen Wang 
1075*48cf7e01SChen Wang 	return 0;
1076*48cf7e01SChen Wang }
1077*48cf7e01SChen Wang 
sg2042_clkgen_probe(struct platform_device * pdev)1078*48cf7e01SChen Wang static int sg2042_clkgen_probe(struct platform_device *pdev)
1079*48cf7e01SChen Wang {
1080*48cf7e01SChen Wang 	struct sg2042_clk_data *clk_data = NULL;
1081*48cf7e01SChen Wang 	int num_clks;
1082*48cf7e01SChen Wang 	int ret;
1083*48cf7e01SChen Wang 
1084*48cf7e01SChen Wang 	num_clks = ARRAY_SIZE(sg2042_div_clks_level_1) +
1085*48cf7e01SChen Wang 		   ARRAY_SIZE(sg2042_div_clks_level_2) +
1086*48cf7e01SChen Wang 		   ARRAY_SIZE(sg2042_gate_clks_level_1) +
1087*48cf7e01SChen Wang 		   ARRAY_SIZE(sg2042_gate_clks_level_2) +
1088*48cf7e01SChen Wang 		   ARRAY_SIZE(sg2042_mux_clks);
1089*48cf7e01SChen Wang 
1090*48cf7e01SChen Wang 	ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
1091*48cf7e01SChen Wang 	if (ret)
1092*48cf7e01SChen Wang 		goto error_out;
1093*48cf7e01SChen Wang 
1094*48cf7e01SChen Wang 	/* level-1 gates */
1095*48cf7e01SChen Wang 	ret = sg2042_clk_register_gates_fw(&pdev->dev, clk_data,
1096*48cf7e01SChen Wang 					   sg2042_gate_clks_level_1,
1097*48cf7e01SChen Wang 					   ARRAY_SIZE(sg2042_gate_clks_level_1));
1098*48cf7e01SChen Wang 	if (ret)
1099*48cf7e01SChen Wang 		goto error_out;
1100*48cf7e01SChen Wang 
1101*48cf7e01SChen Wang 	/* level-1 div */
1102*48cf7e01SChen Wang 	ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_1,
1103*48cf7e01SChen Wang 				       ARRAY_SIZE(sg2042_div_clks_level_1));
1104*48cf7e01SChen Wang 	if (ret)
1105*48cf7e01SChen Wang 		goto error_out;
1106*48cf7e01SChen Wang 
1107*48cf7e01SChen Wang 	/* mux */
1108*48cf7e01SChen Wang 	ret = sg2042_clk_register_muxs(&pdev->dev, clk_data, sg2042_mux_clks,
1109*48cf7e01SChen Wang 				       ARRAY_SIZE(sg2042_mux_clks));
1110*48cf7e01SChen Wang 	if (ret)
1111*48cf7e01SChen Wang 		goto error_out;
1112*48cf7e01SChen Wang 
1113*48cf7e01SChen Wang 	/* level 2 div */
1114*48cf7e01SChen Wang 	ret = sg2042_clk_register_divs(&pdev->dev, clk_data, sg2042_div_clks_level_2,
1115*48cf7e01SChen Wang 				       ARRAY_SIZE(sg2042_div_clks_level_2));
1116*48cf7e01SChen Wang 	if (ret)
1117*48cf7e01SChen Wang 		goto error_out;
1118*48cf7e01SChen Wang 
1119*48cf7e01SChen Wang 	/* level 2 gate */
1120*48cf7e01SChen Wang 	ret = sg2042_clk_register_gates(&pdev->dev, clk_data, sg2042_gate_clks_level_2,
1121*48cf7e01SChen Wang 					ARRAY_SIZE(sg2042_gate_clks_level_2));
1122*48cf7e01SChen Wang 	if (ret)
1123*48cf7e01SChen Wang 		goto error_out;
1124*48cf7e01SChen Wang 
1125*48cf7e01SChen Wang 	return devm_of_clk_add_hw_provider(&pdev->dev,
1126*48cf7e01SChen Wang 					   of_clk_hw_onecell_get,
1127*48cf7e01SChen Wang 					   &clk_data->onecell_data);
1128*48cf7e01SChen Wang 
1129*48cf7e01SChen Wang error_out:
1130*48cf7e01SChen Wang 	pr_err("%s failed error number %d\n", __func__, ret);
1131*48cf7e01SChen Wang 	return ret;
1132*48cf7e01SChen Wang }
1133*48cf7e01SChen Wang 
1134*48cf7e01SChen Wang static const struct of_device_id sg2042_clkgen_match[] = {
1135*48cf7e01SChen Wang 	{ .compatible = "sophgo,sg2042-clkgen" },
1136*48cf7e01SChen Wang 	{ /* sentinel */ }
1137*48cf7e01SChen Wang };
1138*48cf7e01SChen Wang MODULE_DEVICE_TABLE(of, sg2042_clkgen_match);
1139*48cf7e01SChen Wang 
1140*48cf7e01SChen Wang static struct platform_driver sg2042_clkgen_driver = {
1141*48cf7e01SChen Wang 	.probe = sg2042_clkgen_probe,
1142*48cf7e01SChen Wang 	.driver = {
1143*48cf7e01SChen Wang 		.name = "clk-sophgo-sg2042-clkgen",
1144*48cf7e01SChen Wang 		.of_match_table = sg2042_clkgen_match,
1145*48cf7e01SChen Wang 		.suppress_bind_attrs = true,
1146*48cf7e01SChen Wang 	},
1147*48cf7e01SChen Wang };
1148*48cf7e01SChen Wang module_platform_driver(sg2042_clkgen_driver);
1149*48cf7e01SChen Wang 
1150*48cf7e01SChen Wang MODULE_AUTHOR("Chen Wang");
1151*48cf7e01SChen Wang MODULE_DESCRIPTION("Sophgo SG2042 clock generator driver");
1152*48cf7e01SChen Wang MODULE_LICENSE("GPL");
1153