xref: /linux/drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c (revision 522ba450b56fff29f868b1552bdc2965f55de7ed)
1*598e4b67SChen-Yu Tsai // SPDX-License-Identifier: GPL-2.0
2*598e4b67SChen-Yu Tsai /*
3*598e4b67SChen-Yu Tsai  * Copyright (C) 2025 Chen-Yu Tsai <wens@csie.org>
4*598e4b67SChen-Yu Tsai  *
5*598e4b67SChen-Yu Tsai  * Based on the A523 CCU driver:
6*598e4b67SChen-Yu Tsai  *   Copyright (C) 2023-2024 Arm Ltd.
7*598e4b67SChen-Yu Tsai  */
8*598e4b67SChen-Yu Tsai 
9*598e4b67SChen-Yu Tsai #include <linux/clk-provider.h>
10*598e4b67SChen-Yu Tsai #include <linux/io.h>
11*598e4b67SChen-Yu Tsai #include <linux/module.h>
12*598e4b67SChen-Yu Tsai #include <linux/platform_device.h>
13*598e4b67SChen-Yu Tsai 
14*598e4b67SChen-Yu Tsai #include <dt-bindings/clock/sun55i-a523-mcu-ccu.h>
15*598e4b67SChen-Yu Tsai #include <dt-bindings/reset/sun55i-a523-mcu-ccu.h>
16*598e4b67SChen-Yu Tsai 
17*598e4b67SChen-Yu Tsai #include "ccu_common.h"
18*598e4b67SChen-Yu Tsai #include "ccu_reset.h"
19*598e4b67SChen-Yu Tsai 
20*598e4b67SChen-Yu Tsai #include "ccu_div.h"
21*598e4b67SChen-Yu Tsai #include "ccu_gate.h"
22*598e4b67SChen-Yu Tsai #include "ccu_mp.h"
23*598e4b67SChen-Yu Tsai #include "ccu_mult.h"
24*598e4b67SChen-Yu Tsai #include "ccu_nm.h"
25*598e4b67SChen-Yu Tsai 
26*598e4b67SChen-Yu Tsai static const struct clk_parent_data osc24M[] = {
27*598e4b67SChen-Yu Tsai 	{ .fw_name = "hosc" }
28*598e4b67SChen-Yu Tsai };
29*598e4b67SChen-Yu Tsai 
30*598e4b67SChen-Yu Tsai static const struct clk_parent_data ahb[] = {
31*598e4b67SChen-Yu Tsai 	{ .fw_name = "r-ahb" }
32*598e4b67SChen-Yu Tsai };
33*598e4b67SChen-Yu Tsai 
34*598e4b67SChen-Yu Tsai static const struct clk_parent_data apb[] = {
35*598e4b67SChen-Yu Tsai 	{ .fw_name = "r-apb0" }
36*598e4b67SChen-Yu Tsai };
37*598e4b67SChen-Yu Tsai 
38*598e4b67SChen-Yu Tsai #define SUN55I_A523_PLL_AUDIO1_REG	0x00c
39*598e4b67SChen-Yu Tsai static struct ccu_sdm_setting pll_audio1_sdm_table[] = {
40*598e4b67SChen-Yu Tsai 	{ .rate = 2167603200, .pattern = 0xa000a234, .m = 1, .n = 90 }, /* div2->22.5792 */
41*598e4b67SChen-Yu Tsai 	{ .rate = 2359296000, .pattern = 0xa0009ba6, .m = 1, .n = 98 }, /* div2->24.576 */
42*598e4b67SChen-Yu Tsai 	{ .rate = 1806336000, .pattern = 0xa000872b, .m = 1, .n = 75 }, /* div5->22.576 */
43*598e4b67SChen-Yu Tsai };
44*598e4b67SChen-Yu Tsai 
45*598e4b67SChen-Yu Tsai static struct ccu_nm pll_audio1_clk = {
46*598e4b67SChen-Yu Tsai 	.enable		= BIT(27),
47*598e4b67SChen-Yu Tsai 	.lock		= BIT(28),
48*598e4b67SChen-Yu Tsai 	.n		= _SUNXI_CCU_MULT_MIN(8, 8, 11),
49*598e4b67SChen-Yu Tsai 	.m		= _SUNXI_CCU_DIV(1, 1),
50*598e4b67SChen-Yu Tsai 	.sdm		= _SUNXI_CCU_SDM(pll_audio1_sdm_table, BIT(24),
51*598e4b67SChen-Yu Tsai 					 0x010, BIT(31)),
52*598e4b67SChen-Yu Tsai 	.min_rate	= 180000000U,
53*598e4b67SChen-Yu Tsai 	.max_rate	= 3500000000U,
54*598e4b67SChen-Yu Tsai 	.common		= {
55*598e4b67SChen-Yu Tsai 		.reg		= 0x00c,
56*598e4b67SChen-Yu Tsai 		.features	= CCU_FEATURE_SIGMA_DELTA_MOD,
57*598e4b67SChen-Yu Tsai 		.hw.init	= CLK_HW_INIT_PARENTS_DATA("pll-audio1",
58*598e4b67SChen-Yu Tsai 							   osc24M, &ccu_nm_ops,
59*598e4b67SChen-Yu Tsai 							   CLK_SET_RATE_GATE),
60*598e4b67SChen-Yu Tsai 	},
61*598e4b67SChen-Yu Tsai };
62*598e4b67SChen-Yu Tsai 
63*598e4b67SChen-Yu Tsai /*
64*598e4b67SChen-Yu Tsai  * /2 and /5 dividers are actually programmable, but we just use the
65*598e4b67SChen-Yu Tsai  * values from the BSP, since the audio PLL only needs to provide a
66*598e4b67SChen-Yu Tsai  * couple clock rates. This also matches the names given in the manual.
67*598e4b67SChen-Yu Tsai  */
68*598e4b67SChen-Yu Tsai static const struct clk_hw *pll_audio1_div_parents[] = { &pll_audio1_clk.common.hw };
69*598e4b67SChen-Yu Tsai static CLK_FIXED_FACTOR_HWS(pll_audio1_div2_clk, "pll-audio1-div2",
70*598e4b67SChen-Yu Tsai 			    pll_audio1_div_parents, 2, 1,
71*598e4b67SChen-Yu Tsai 			    CLK_SET_RATE_PARENT);
72*598e4b67SChen-Yu Tsai static CLK_FIXED_FACTOR_HWS(pll_audio1_div5_clk, "pll-audio1-div5",
73*598e4b67SChen-Yu Tsai 			    pll_audio1_div_parents, 5, 1,
74*598e4b67SChen-Yu Tsai 			    CLK_SET_RATE_PARENT);
75*598e4b67SChen-Yu Tsai 
76*598e4b67SChen-Yu Tsai static SUNXI_CCU_M_WITH_GATE(audio_out_clk, "audio-out",
77*598e4b67SChen-Yu Tsai 			     "pll-audio1-div2", 0x01c,
78*598e4b67SChen-Yu Tsai 			     0, 5, BIT(31), CLK_SET_RATE_PARENT);
79*598e4b67SChen-Yu Tsai 
80*598e4b67SChen-Yu Tsai static const struct clk_parent_data dsp_parents[] = {
81*598e4b67SChen-Yu Tsai 	{ .fw_name = "hosc" },
82*598e4b67SChen-Yu Tsai 	{ .fw_name = "losc" },
83*598e4b67SChen-Yu Tsai 	{ .fw_name = "iosc" },
84*598e4b67SChen-Yu Tsai 	/*
85*598e4b67SChen-Yu Tsai 	 * The order of the following two parent is from the BSP code. It is
86*598e4b67SChen-Yu Tsai 	 * the opposite in the manual. Testing with the DSP is required to
87*598e4b67SChen-Yu Tsai 	 * figure out the real order.
88*598e4b67SChen-Yu Tsai 	 */
89*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div5_clk.hw },
90*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div2_clk.hw },
91*598e4b67SChen-Yu Tsai 	{ .fw_name = "dsp" },
92*598e4b67SChen-Yu Tsai };
93*598e4b67SChen-Yu Tsai static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dsp_clk, "mcu-dsp", dsp_parents, 0x0020,
94*598e4b67SChen-Yu Tsai 				      0, 5,	/* M */
95*598e4b67SChen-Yu Tsai 				      24, 3,	/* mux */
96*598e4b67SChen-Yu Tsai 				      BIT(31),	/* gate */
97*598e4b67SChen-Yu Tsai 				      0);
98*598e4b67SChen-Yu Tsai 
99*598e4b67SChen-Yu Tsai static const struct clk_parent_data i2s_parents[] = {
100*598e4b67SChen-Yu Tsai 	{ .fw_name = "pll-audio0-4x" },
101*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div2_clk.hw },
102*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div5_clk.hw },
103*598e4b67SChen-Yu Tsai };
104*598e4b67SChen-Yu Tsai 
105*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(i2s0_clk, "i2s0", i2s_parents, 0x02c,
106*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
107*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
108*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
109*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
110*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
111*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(i2s1_clk, "i2s1", i2s_parents, 0x030,
112*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
113*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
114*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
115*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
116*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
117*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(i2s2_clk, "i2s2", i2s_parents, 0x034,
118*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
119*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
120*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
121*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
122*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
123*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(i2s3_clk, "i2s3", i2s_parents, 0x038,
124*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
125*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
126*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
127*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
128*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
129*598e4b67SChen-Yu Tsai 
130*598e4b67SChen-Yu Tsai static const struct clk_parent_data i2s3_asrc_parents[] = {
131*598e4b67SChen-Yu Tsai 	{ .fw_name = "pll-periph0-300m" },
132*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div2_clk.hw },
133*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div5_clk.hw },
134*598e4b67SChen-Yu Tsai };
135*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(i2s3_asrc_clk, "i2s3-asrc",
136*598e4b67SChen-Yu Tsai 				  i2s3_asrc_parents, 0x03c,
137*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
138*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
139*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
140*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
141*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
142*598e4b67SChen-Yu Tsai 
143*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_i2s0_clk, "bus-i2s0", apb, 0x040, BIT(0), 0);
144*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_i2s1_clk, "bus-i2s1", apb, 0x040, BIT(1), 0);
145*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_i2s2_clk, "bus-i2s2", apb, 0x040, BIT(2), 0);
146*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_i2s3_clk, "bus-i2s3", apb, 0x040, BIT(3), 0);
147*598e4b67SChen-Yu Tsai 
148*598e4b67SChen-Yu Tsai static const struct clk_parent_data audio_parents[] = {
149*598e4b67SChen-Yu Tsai 	{ .fw_name = "pll-audio0-4x" },
150*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div2_clk.hw },
151*598e4b67SChen-Yu Tsai 	{ .hw = &pll_audio1_div5_clk.hw },
152*598e4b67SChen-Yu Tsai };
153*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(spdif_tx_clk, "spdif-tx",
154*598e4b67SChen-Yu Tsai 				  audio_parents, 0x044,
155*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
156*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
157*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
158*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
159*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
160*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(spdif_rx_clk, "spdif-rx",
161*598e4b67SChen-Yu Tsai 				  i2s3_asrc_parents, 0x048,
162*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
163*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
164*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
165*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
166*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
167*598e4b67SChen-Yu Tsai 
168*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_spdif_clk, "bus-spdif", apb, 0x04c, BIT(0), 0);
169*598e4b67SChen-Yu Tsai 
170*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(dmic_clk, "dmic", audio_parents, 0x050,
171*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
172*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
173*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
174*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
175*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
176*598e4b67SChen-Yu Tsai 
177*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_dmic_clk, "bus-dmic", apb, 0x054, BIT(0), 0);
178*598e4b67SChen-Yu Tsai 
179*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(audio_dac_clk, "audio-dac",
180*598e4b67SChen-Yu Tsai 				  audio_parents, 0x058,
181*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
182*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
183*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
184*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
185*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
186*598e4b67SChen-Yu Tsai static SUNXI_CCU_DUALDIV_MUX_GATE(audio_adc_clk, "audio-adc",
187*598e4b67SChen-Yu Tsai 				  audio_parents, 0x05c,
188*598e4b67SChen-Yu Tsai 				  0, 5,		/* M */
189*598e4b67SChen-Yu Tsai 				  5, 5,		/* P */
190*598e4b67SChen-Yu Tsai 				  24, 3,	/* mux */
191*598e4b67SChen-Yu Tsai 				  BIT(31),	/* gate */
192*598e4b67SChen-Yu Tsai 				  CLK_SET_RATE_PARENT);
193*598e4b67SChen-Yu Tsai 
194*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_audio_codec_clk, "bus-audio-codec",
195*598e4b67SChen-Yu Tsai 			   apb, 0x060, BIT(0), 0);
196*598e4b67SChen-Yu Tsai 
197*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_dsp_msgbox_clk, "bus-dsp-msgbox",
198*598e4b67SChen-Yu Tsai 			   ahb, 0x068, BIT(0), 0);
199*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_dsp_cfg_clk, "bus-dsp-cfg",
200*598e4b67SChen-Yu Tsai 			   apb, 0x06c, BIT(0), 0);
201*598e4b67SChen-Yu Tsai 
202*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_npu_hclk, "bus-npu-hclk", ahb, 0x070, BIT(1), 0);
203*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_npu_aclk, "bus-npu-aclk", ahb, 0x070, BIT(2), 0);
204*598e4b67SChen-Yu Tsai 
205*598e4b67SChen-Yu Tsai static const struct clk_parent_data timer_parents[] = {
206*598e4b67SChen-Yu Tsai 	{ .fw_name = "hosc" },
207*598e4b67SChen-Yu Tsai 	{ .fw_name = "losc" },
208*598e4b67SChen-Yu Tsai 	{ .fw_name = "iosc" },
209*598e4b67SChen-Yu Tsai 	{ .fw_name = "r-ahb" }
210*598e4b67SChen-Yu Tsai };
211*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer0_clk, "mcu-timer0", timer_parents,
212*598e4b67SChen-Yu Tsai 				      0x074,
213*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
214*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
215*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
216*598e4b67SChen-Yu Tsai 				      0);
217*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer1_clk, "mcu-timer1", timer_parents,
218*598e4b67SChen-Yu Tsai 				      0x078,
219*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
220*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
221*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
222*598e4b67SChen-Yu Tsai 				      0);
223*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer2_clk, "mcu-timer2", timer_parents,
224*598e4b67SChen-Yu Tsai 				      0x07c,
225*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
226*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
227*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
228*598e4b67SChen-Yu Tsai 				      0);
229*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer3_clk, "mcu-timer3", timer_parents,
230*598e4b67SChen-Yu Tsai 				      0x080,
231*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
232*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
233*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
234*598e4b67SChen-Yu Tsai 				      0);
235*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer4_clk, "mcu-timer4", timer_parents,
236*598e4b67SChen-Yu Tsai 				      0x084,
237*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
238*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
239*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
240*598e4b67SChen-Yu Tsai 				      0);
241*598e4b67SChen-Yu Tsai static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer5_clk, "mcu-timer5", timer_parents,
242*598e4b67SChen-Yu Tsai 				      0x088,
243*598e4b67SChen-Yu Tsai 				      1, 3,	/* P */
244*598e4b67SChen-Yu Tsai 				      4, 2,	/* mux */
245*598e4b67SChen-Yu Tsai 				      BIT(0),	/* gate */
246*598e4b67SChen-Yu Tsai 				      0);
247*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_mcu_timer_clk, "bus-mcu-timer", ahb, 0x08c, BIT(0), 0);
248*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_mcu_dma_clk, "bus-mcu-dma", ahb, 0x104, BIT(0), 0);
249*598e4b67SChen-Yu Tsai /* tzma* only found in BSP code. */
250*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(tzma0_clk, "tzma0", ahb, 0x108, BIT(0), 0);
251*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(tzma1_clk, "tzma1", ahb, 0x10c, BIT(0), 0);
252*598e4b67SChen-Yu Tsai /* parent is a guess as this block is not shown in the system bus tree diagram */
253*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_pubsram_clk, "bus-pubsram", ahb, 0x114, BIT(0), 0);
254*598e4b67SChen-Yu Tsai 
255*598e4b67SChen-Yu Tsai /*
256*598e4b67SChen-Yu Tsai  * user manual has "mbus" clock as parent of both clocks below,
257*598e4b67SChen-Yu Tsai  * but this makes more sense, since BSP MCU DMA controller has
258*598e4b67SChen-Yu Tsai  * reference to both of them, likely needing both enabled.
259*598e4b67SChen-Yu Tsai  */
260*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_FW(mbus_mcu_clk, "mbus-mcu", "mbus", 0x11c, BIT(1), 0);
261*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_HW(mbus_mcu_dma_clk, "mbus-mcu-dma",
262*598e4b67SChen-Yu Tsai 			 &mbus_mcu_clk.common.hw, 0x11c, BIT(0), 0);
263*598e4b67SChen-Yu Tsai 
264*598e4b67SChen-Yu Tsai static const struct clk_parent_data riscv_pwm_parents[] = {
265*598e4b67SChen-Yu Tsai 	{ .fw_name = "hosc" },
266*598e4b67SChen-Yu Tsai 	{ .fw_name = "losc" },
267*598e4b67SChen-Yu Tsai 	{ .fw_name = "iosc" },
268*598e4b67SChen-Yu Tsai };
269*598e4b67SChen-Yu Tsai 
270*598e4b67SChen-Yu Tsai static SUNXI_CCU_MUX_DATA_WITH_GATE(riscv_clk, "riscv",
271*598e4b67SChen-Yu Tsai 				    riscv_pwm_parents, 0x120,
272*598e4b67SChen-Yu Tsai 				    27, 3, BIT(31), 0);
273*598e4b67SChen-Yu Tsai /* Parents are guesses as these two blocks are not shown in the system bus tree diagram */
274*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_riscv_cfg_clk, "bus-riscv-cfg", ahb,
275*598e4b67SChen-Yu Tsai 			   0x124, BIT(0), 0);
276*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_riscv_msgbox_clk, "bus-riscv-msgbox", ahb,
277*598e4b67SChen-Yu Tsai 			   0x128, BIT(0), 0);
278*598e4b67SChen-Yu Tsai 
279*598e4b67SChen-Yu Tsai static SUNXI_CCU_MUX_DATA_WITH_GATE(mcu_pwm0_clk, "mcu-pwm0",
280*598e4b67SChen-Yu Tsai 				    riscv_pwm_parents, 0x130,
281*598e4b67SChen-Yu Tsai 				    24, 3, BIT(31), 0);
282*598e4b67SChen-Yu Tsai static SUNXI_CCU_GATE_DATA(bus_mcu_pwm0_clk, "bus-mcu-pwm0", apb,
283*598e4b67SChen-Yu Tsai 			   0x134, BIT(0), 0);
284*598e4b67SChen-Yu Tsai 
285*598e4b67SChen-Yu Tsai /*
286*598e4b67SChen-Yu Tsai  * Contains all clocks that are controlled by a hardware register. They
287*598e4b67SChen-Yu Tsai  * have a (sunxi) .common member, which needs to be initialised by the common
288*598e4b67SChen-Yu Tsai  * sunxi CCU code, to be filled with the MMIO base address and the shared lock.
289*598e4b67SChen-Yu Tsai  */
290*598e4b67SChen-Yu Tsai static struct ccu_common *sun55i_a523_mcu_ccu_clks[] = {
291*598e4b67SChen-Yu Tsai 	&pll_audio1_clk.common,
292*598e4b67SChen-Yu Tsai 	&audio_out_clk.common,
293*598e4b67SChen-Yu Tsai 	&dsp_clk.common,
294*598e4b67SChen-Yu Tsai 	&i2s0_clk.common,
295*598e4b67SChen-Yu Tsai 	&i2s1_clk.common,
296*598e4b67SChen-Yu Tsai 	&i2s2_clk.common,
297*598e4b67SChen-Yu Tsai 	&i2s3_clk.common,
298*598e4b67SChen-Yu Tsai 	&i2s3_asrc_clk.common,
299*598e4b67SChen-Yu Tsai 	&bus_i2s0_clk.common,
300*598e4b67SChen-Yu Tsai 	&bus_i2s1_clk.common,
301*598e4b67SChen-Yu Tsai 	&bus_i2s2_clk.common,
302*598e4b67SChen-Yu Tsai 	&bus_i2s3_clk.common,
303*598e4b67SChen-Yu Tsai 	&spdif_tx_clk.common,
304*598e4b67SChen-Yu Tsai 	&spdif_rx_clk.common,
305*598e4b67SChen-Yu Tsai 	&bus_spdif_clk.common,
306*598e4b67SChen-Yu Tsai 	&dmic_clk.common,
307*598e4b67SChen-Yu Tsai 	&bus_dmic_clk.common,
308*598e4b67SChen-Yu Tsai 	&audio_dac_clk.common,
309*598e4b67SChen-Yu Tsai 	&audio_adc_clk.common,
310*598e4b67SChen-Yu Tsai 	&bus_audio_codec_clk.common,
311*598e4b67SChen-Yu Tsai 	&bus_dsp_msgbox_clk.common,
312*598e4b67SChen-Yu Tsai 	&bus_dsp_cfg_clk.common,
313*598e4b67SChen-Yu Tsai 	&bus_npu_aclk.common,
314*598e4b67SChen-Yu Tsai 	&bus_npu_hclk.common,
315*598e4b67SChen-Yu Tsai 	&mcu_timer0_clk.common,
316*598e4b67SChen-Yu Tsai 	&mcu_timer1_clk.common,
317*598e4b67SChen-Yu Tsai 	&mcu_timer2_clk.common,
318*598e4b67SChen-Yu Tsai 	&mcu_timer3_clk.common,
319*598e4b67SChen-Yu Tsai 	&mcu_timer4_clk.common,
320*598e4b67SChen-Yu Tsai 	&mcu_timer5_clk.common,
321*598e4b67SChen-Yu Tsai 	&bus_mcu_timer_clk.common,
322*598e4b67SChen-Yu Tsai 	&bus_mcu_dma_clk.common,
323*598e4b67SChen-Yu Tsai 	&tzma0_clk.common,
324*598e4b67SChen-Yu Tsai 	&tzma1_clk.common,
325*598e4b67SChen-Yu Tsai 	&bus_pubsram_clk.common,
326*598e4b67SChen-Yu Tsai 	&mbus_mcu_dma_clk.common,
327*598e4b67SChen-Yu Tsai 	&mbus_mcu_clk.common,
328*598e4b67SChen-Yu Tsai 	&riscv_clk.common,
329*598e4b67SChen-Yu Tsai 	&bus_riscv_cfg_clk.common,
330*598e4b67SChen-Yu Tsai 	&bus_riscv_msgbox_clk.common,
331*598e4b67SChen-Yu Tsai 	&mcu_pwm0_clk.common,
332*598e4b67SChen-Yu Tsai 	&bus_mcu_pwm0_clk.common,
333*598e4b67SChen-Yu Tsai };
334*598e4b67SChen-Yu Tsai 
335*598e4b67SChen-Yu Tsai static struct clk_hw_onecell_data sun55i_a523_mcu_hw_clks = {
336*598e4b67SChen-Yu Tsai 	.hws	= {
337*598e4b67SChen-Yu Tsai 		[CLK_MCU_PLL_AUDIO1]		= &pll_audio1_clk.common.hw,
338*598e4b67SChen-Yu Tsai 		[CLK_MCU_PLL_AUDIO1_DIV2]	= &pll_audio1_div2_clk.hw,
339*598e4b67SChen-Yu Tsai 		[CLK_MCU_PLL_AUDIO1_DIV5]	= &pll_audio1_div5_clk.hw,
340*598e4b67SChen-Yu Tsai 		[CLK_MCU_AUDIO_OUT]		= &audio_out_clk.common.hw,
341*598e4b67SChen-Yu Tsai 		[CLK_MCU_DSP]			= &dsp_clk.common.hw,
342*598e4b67SChen-Yu Tsai 		[CLK_MCU_I2S0]			= &i2s0_clk.common.hw,
343*598e4b67SChen-Yu Tsai 		[CLK_MCU_I2S1]			= &i2s1_clk.common.hw,
344*598e4b67SChen-Yu Tsai 		[CLK_MCU_I2S2]			= &i2s2_clk.common.hw,
345*598e4b67SChen-Yu Tsai 		[CLK_MCU_I2S3]			= &i2s3_clk.common.hw,
346*598e4b67SChen-Yu Tsai 		[CLK_MCU_I2S3_ASRC]		= &i2s3_asrc_clk.common.hw,
347*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_I2S0]		= &bus_i2s0_clk.common.hw,
348*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_I2S1]		= &bus_i2s1_clk.common.hw,
349*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_I2S2]		= &bus_i2s2_clk.common.hw,
350*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_I2S3]		= &bus_i2s3_clk.common.hw,
351*598e4b67SChen-Yu Tsai 		[CLK_MCU_SPDIF_TX]		= &spdif_tx_clk.common.hw,
352*598e4b67SChen-Yu Tsai 		[CLK_MCU_SPDIF_RX]		= &spdif_rx_clk.common.hw,
353*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_SPDIF]		= &bus_spdif_clk.common.hw,
354*598e4b67SChen-Yu Tsai 		[CLK_MCU_DMIC]			= &dmic_clk.common.hw,
355*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_DMIC]		= &bus_dmic_clk.common.hw,
356*598e4b67SChen-Yu Tsai 		[CLK_MCU_AUDIO_CODEC_DAC]	= &audio_dac_clk.common.hw,
357*598e4b67SChen-Yu Tsai 		[CLK_MCU_AUDIO_CODEC_ADC]	= &audio_adc_clk.common.hw,
358*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_AUDIO_CODEC]	= &bus_audio_codec_clk.common.hw,
359*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_DSP_MSGBOX]	= &bus_dsp_msgbox_clk.common.hw,
360*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_DSP_CFG]		= &bus_dsp_cfg_clk.common.hw,
361*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_NPU_HCLK]		= &bus_npu_hclk.common.hw,
362*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_NPU_ACLK]		= &bus_npu_aclk.common.hw,
363*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER0]		= &mcu_timer0_clk.common.hw,
364*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER1]		= &mcu_timer1_clk.common.hw,
365*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER2]		= &mcu_timer2_clk.common.hw,
366*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER3]		= &mcu_timer3_clk.common.hw,
367*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER4]		= &mcu_timer4_clk.common.hw,
368*598e4b67SChen-Yu Tsai 		[CLK_MCU_TIMER5]		= &mcu_timer5_clk.common.hw,
369*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_TIMER]		= &bus_mcu_timer_clk.common.hw,
370*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_DMA]		= &bus_mcu_dma_clk.common.hw,
371*598e4b67SChen-Yu Tsai 		[CLK_MCU_TZMA0]			= &tzma0_clk.common.hw,
372*598e4b67SChen-Yu Tsai 		[CLK_MCU_TZMA1]			= &tzma1_clk.common.hw,
373*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_PUBSRAM]		= &bus_pubsram_clk.common.hw,
374*598e4b67SChen-Yu Tsai 		[CLK_MCU_MBUS_DMA]		= &mbus_mcu_dma_clk.common.hw,
375*598e4b67SChen-Yu Tsai 		[CLK_MCU_MBUS]			= &mbus_mcu_clk.common.hw,
376*598e4b67SChen-Yu Tsai 		[CLK_MCU_RISCV]			= &riscv_clk.common.hw,
377*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_RISCV_CFG]		= &bus_riscv_cfg_clk.common.hw,
378*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_RISCV_MSGBOX]	= &bus_riscv_msgbox_clk.common.hw,
379*598e4b67SChen-Yu Tsai 		[CLK_MCU_PWM0]			= &mcu_pwm0_clk.common.hw,
380*598e4b67SChen-Yu Tsai 		[CLK_BUS_MCU_PWM0]		= &bus_mcu_pwm0_clk.common.hw,
381*598e4b67SChen-Yu Tsai 	},
382*598e4b67SChen-Yu Tsai 	.num	= CLK_BUS_MCU_PWM0 + 1,
383*598e4b67SChen-Yu Tsai };
384*598e4b67SChen-Yu Tsai 
385*598e4b67SChen-Yu Tsai static struct ccu_reset_map sun55i_a523_mcu_ccu_resets[] = {
386*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_I2S0]		= { 0x0040, BIT(16) },
387*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_I2S1]		= { 0x0040, BIT(17) },
388*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_I2S2]		= { 0x0040, BIT(18) },
389*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_I2S3]		= { 0x0040, BIT(19) },
390*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_SPDIF]		= { 0x004c, BIT(16) },
391*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DMIC]		= { 0x0054, BIT(16) },
392*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_AUDIO_CODEC]	= { 0x0060, BIT(16) },
393*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DSP_MSGBOX]	= { 0x0068, BIT(16) },
394*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DSP_CFG]		= { 0x006c, BIT(16) },
395*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_NPU]		= { 0x0070, BIT(16) },
396*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_TIMER]		= { 0x008c, BIT(16) },
397*598e4b67SChen-Yu Tsai 	/* dsp and dsp_debug resets only found in BSP code. */
398*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DSP_DEBUG]		= { 0x0100, BIT(16) },
399*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DSP]		= { 0x0100, BIT(17) },
400*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_DMA]		= { 0x0104, BIT(16) },
401*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_PUBSRAM]		= { 0x0114, BIT(16) },
402*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_RISCV_CFG]		= { 0x0124, BIT(16) },
403*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_RISCV_DEBUG]	= { 0x0124, BIT(17) },
404*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_RISCV_CORE]	= { 0x0124, BIT(18) },
405*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_RISCV_MSGBOX]	= { 0x0128, BIT(16) },
406*598e4b67SChen-Yu Tsai 	[RST_BUS_MCU_PWM0]		= { 0x0134, BIT(16) },
407*598e4b67SChen-Yu Tsai };
408*598e4b67SChen-Yu Tsai 
409*598e4b67SChen-Yu Tsai static const struct sunxi_ccu_desc sun55i_a523_mcu_ccu_desc = {
410*598e4b67SChen-Yu Tsai 	.ccu_clks	= sun55i_a523_mcu_ccu_clks,
411*598e4b67SChen-Yu Tsai 	.num_ccu_clks	= ARRAY_SIZE(sun55i_a523_mcu_ccu_clks),
412*598e4b67SChen-Yu Tsai 
413*598e4b67SChen-Yu Tsai 	.hw_clks	= &sun55i_a523_mcu_hw_clks,
414*598e4b67SChen-Yu Tsai 
415*598e4b67SChen-Yu Tsai 	.resets		= sun55i_a523_mcu_ccu_resets,
416*598e4b67SChen-Yu Tsai 	.num_resets	= ARRAY_SIZE(sun55i_a523_mcu_ccu_resets),
417*598e4b67SChen-Yu Tsai };
418*598e4b67SChen-Yu Tsai 
sun55i_a523_mcu_ccu_probe(struct platform_device * pdev)419*598e4b67SChen-Yu Tsai static int sun55i_a523_mcu_ccu_probe(struct platform_device *pdev)
420*598e4b67SChen-Yu Tsai {
421*598e4b67SChen-Yu Tsai 	void __iomem *reg;
422*598e4b67SChen-Yu Tsai 	u32 val;
423*598e4b67SChen-Yu Tsai 	int ret;
424*598e4b67SChen-Yu Tsai 
425*598e4b67SChen-Yu Tsai 	reg = devm_platform_ioremap_resource(pdev, 0);
426*598e4b67SChen-Yu Tsai 	if (IS_ERR(reg))
427*598e4b67SChen-Yu Tsai 		return PTR_ERR(reg);
428*598e4b67SChen-Yu Tsai 
429*598e4b67SChen-Yu Tsai 	val = readl(reg + SUN55I_A523_PLL_AUDIO1_REG);
430*598e4b67SChen-Yu Tsai 
431*598e4b67SChen-Yu Tsai 	/*
432*598e4b67SChen-Yu Tsai 	 * The PLL clock code does not model all bits, for instance it does
433*598e4b67SChen-Yu Tsai 	 * not support a separate enable and gate bit. We present the
434*598e4b67SChen-Yu Tsai 	 * gate bit(27) as the enable bit, but then have to set the
435*598e4b67SChen-Yu Tsai 	 * PLL Enable, LDO Enable, and Lock Enable bits on all PLLs here.
436*598e4b67SChen-Yu Tsai 	 */
437*598e4b67SChen-Yu Tsai 	val |= BIT(31) | BIT(30) | BIT(29);
438*598e4b67SChen-Yu Tsai 
439*598e4b67SChen-Yu Tsai 	/* Enforce p1 = 5, p0 = 2 (the default) for PLL_AUDIO1 */
440*598e4b67SChen-Yu Tsai 	val &= ~(GENMASK(22, 20) | GENMASK(18, 16));
441*598e4b67SChen-Yu Tsai 	val |= (4 << 20) | (1 << 16);
442*598e4b67SChen-Yu Tsai 
443*598e4b67SChen-Yu Tsai 	writel(val, reg + SUN55I_A523_PLL_AUDIO1_REG);
444*598e4b67SChen-Yu Tsai 
445*598e4b67SChen-Yu Tsai 	ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun55i_a523_mcu_ccu_desc);
446*598e4b67SChen-Yu Tsai 	if (ret)
447*598e4b67SChen-Yu Tsai 		return ret;
448*598e4b67SChen-Yu Tsai 
449*598e4b67SChen-Yu Tsai 	return 0;
450*598e4b67SChen-Yu Tsai }
451*598e4b67SChen-Yu Tsai 
452*598e4b67SChen-Yu Tsai static const struct of_device_id sun55i_a523_mcu_ccu_ids[] = {
453*598e4b67SChen-Yu Tsai 	{ .compatible = "allwinner,sun55i-a523-mcu-ccu" },
454*598e4b67SChen-Yu Tsai 	{ }
455*598e4b67SChen-Yu Tsai };
456*598e4b67SChen-Yu Tsai 
457*598e4b67SChen-Yu Tsai static struct platform_driver sun55i_a523_mcu_ccu_driver = {
458*598e4b67SChen-Yu Tsai 	.probe	= sun55i_a523_mcu_ccu_probe,
459*598e4b67SChen-Yu Tsai 	.driver	= {
460*598e4b67SChen-Yu Tsai 		.name			= "sun55i-a523-mcu-ccu",
461*598e4b67SChen-Yu Tsai 		.suppress_bind_attrs	= true,
462*598e4b67SChen-Yu Tsai 		.of_match_table		= sun55i_a523_mcu_ccu_ids,
463*598e4b67SChen-Yu Tsai 	},
464*598e4b67SChen-Yu Tsai };
465*598e4b67SChen-Yu Tsai module_platform_driver(sun55i_a523_mcu_ccu_driver);
466*598e4b67SChen-Yu Tsai 
467*598e4b67SChen-Yu Tsai MODULE_IMPORT_NS("SUNXI_CCU");
468*598e4b67SChen-Yu Tsai MODULE_DESCRIPTION("Support for the Allwinner A523 MCU CCU");
469*598e4b67SChen-Yu Tsai MODULE_LICENSE("GPL");
470