1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Ingenic JZ4755 SoC CGU driver
4 * Heavily based on JZ4725b CGU driver
5 *
6 * Copyright (C) 2022 Siarhei Volkau
7 * Author: Siarhei Volkau <lis8215@gmail.com>
8 */
9
10#include <linux/clk-provider.h>
11#include <linux/delay.h>
12#include <linux/of.h>
13
14#include <dt-bindings/clock/ingenic,jz4755-cgu.h>
15
16#include "cgu.h"
17#include "pm.h"
18
19/* CGU register offsets */
20#define CGU_REG_CPCCR 0x00
21#define CGU_REG_CPPCR 0x10
22#define CGU_REG_CLKGR 0x20
23#define CGU_REG_OPCR 0x24
24#define CGU_REG_I2SCDR 0x60
25#define CGU_REG_LPCDR 0x64
26#define CGU_REG_MSCCDR 0x68
27#define CGU_REG_SSICDR 0x74
28#define CGU_REG_CIMCDR 0x7C
29
30static struct ingenic_cgu *cgu;
31
32static const s8 pll_od_encoding[4] = {
33 0x0, 0x1, -1, 0x3,
34};
35
36static const u8 jz4755_cgu_cpccr_div_table[] = {
37 1, 2, 3, 4, 6, 8,
38};
39
40static const u8 jz4755_cgu_pll_half_div_table[] = {
41 2, 1,
42};
43
44static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = {
45
46 /* External clocks */
47
48 [JZ4755_CLK_EXT] = { "ext", CGU_CLK_EXT },
49 [JZ4755_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
50
51 [JZ4755_CLK_PLL] = {
52 "pll", CGU_CLK_PLL,
53 .parents = { JZ4755_CLK_EXT, },
54 .pll = {
55 .reg = CGU_REG_CPPCR,
56 .rate_multiplier = 1,
57 .m_shift = 23,
58 .m_bits = 9,
59 .m_offset = 2,
60 .n_shift = 18,
61 .n_bits = 5,
62 .n_offset = 2,
63 .od_shift = 16,
64 .od_bits = 2,
65 .od_max = 4,
66 .od_encoding = pll_od_encoding,
67 .stable_bit = 10,
68 .bypass_reg = CGU_REG_CPPCR,
69 .bypass_bit = 9,
70 .enable_bit = 8,
71 },
72 },
73
74 /* Muxes & dividers */
75
76 [JZ4755_CLK_PLL_HALF] = {
77 "pll half", CGU_CLK_DIV,
78 .parents = { JZ4755_CLK_PLL, },
79 .div = {
80 CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
81 jz4755_cgu_pll_half_div_table,
82 },
83 },
84
85 [JZ4755_CLK_EXT_HALF] = {
86 "ext half", CGU_CLK_DIV,
87 .parents = { JZ4755_CLK_EXT, },
88 .div = {
89 CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0,
90 NULL,
91 },
92 },
93
94 [JZ4755_CLK_CCLK] = {
95 "cclk", CGU_CLK_DIV,
96 .parents = { JZ4755_CLK_PLL, },
97 .div = {
98 CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
99 jz4755_cgu_cpccr_div_table,
100 },
101 },
102
103 [JZ4755_CLK_H0CLK] = {
104 "hclk", CGU_CLK_DIV,
105 .parents = { JZ4755_CLK_PLL, },
106 .div = {
107 CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
108 jz4755_cgu_cpccr_div_table,
109 },
110 },
111
112 [JZ4755_CLK_PCLK] = {
113 "pclk", CGU_CLK_DIV,
114 .parents = { JZ4755_CLK_PLL, },
115 .div = {
116 CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
117 jz4755_cgu_cpccr_div_table,
118 },
119 },
120
121 [JZ4755_CLK_MCLK] = {
122 "mclk", CGU_CLK_DIV,
123 .parents = { JZ4755_CLK_PLL, },
124 .div = {
125 CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
126 jz4755_cgu_cpccr_div_table,
127 },
128 },
129
130 [JZ4755_CLK_H1CLK] = {
131 "h1clk", CGU_CLK_DIV,
132 .parents = { JZ4755_CLK_PLL, },
133 .div = {
134 CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
135 jz4755_cgu_cpccr_div_table,
136 },
137 },
138
139 [JZ4755_CLK_UDC] = {
140 "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
141 .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, },
142 .mux = { CGU_REG_CPCCR, 29, 1 },
143 .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
144 .gate = { CGU_REG_CLKGR, 10 },
145 },
146
147 [JZ4755_CLK_LCD] = {
148 "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
149 .parents = { JZ4755_CLK_PLL_HALF, },
150 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
151 .gate = { CGU_REG_CLKGR, 9 },
152 },
153
154 [JZ4755_CLK_MMC] = {
155 "mmc", CGU_CLK_DIV,
156 .parents = { JZ4755_CLK_PLL_HALF, },
157 .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
158 },
159
160 [JZ4755_CLK_I2S] = {
161 "i2s", CGU_CLK_MUX | CGU_CLK_DIV,
162 .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, },
163 .mux = { CGU_REG_CPCCR, 31, 1 },
164 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
165 },
166
167 [JZ4755_CLK_SPI] = {
168 "spi", CGU_CLK_DIV | CGU_CLK_GATE,
169 .parents = { JZ4755_CLK_PLL_HALF, },
170 .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
171 .gate = { CGU_REG_CLKGR, 4 },
172 },
173
174 [JZ4755_CLK_TVE] = {
175 "tve", CGU_CLK_MUX | CGU_CLK_GATE,
176 .parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, },
177 .mux = { CGU_REG_LPCDR, 31, 1 },
178 .gate = { CGU_REG_CLKGR, 18 },
179 },
180
181 [JZ4755_CLK_RTC] = {
182 "rtc", CGU_CLK_MUX | CGU_CLK_GATE,
183 .parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, },
184 .mux = { CGU_REG_OPCR, 2, 1},
185 .gate = { CGU_REG_CLKGR, 2 },
186 },
187
188 [JZ4755_CLK_CIM] = {
189 "cim", CGU_CLK_DIV | CGU_CLK_GATE,
190 .parents = { JZ4755_CLK_PLL_HALF, },
191 .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
192 .gate = { CGU_REG_CLKGR, 8 },
193 },
194
195 /* Gate-only clocks */
196
197 [JZ4755_CLK_UART0] = {
198 "uart0", CGU_CLK_GATE,
199 .parents = { JZ4755_CLK_EXT_HALF, },
200 .gate = { CGU_REG_CLKGR, 0 },
201 },
202
203 [JZ4755_CLK_UART1] = {
204 "uart1", CGU_CLK_GATE,
205 .parents = { JZ4755_CLK_EXT_HALF, },
206 .gate = { CGU_REG_CLKGR, 14 },
207 },
208
209 [JZ4755_CLK_UART2] = {
210 "uart2", CGU_CLK_GATE,
211 .parents = { JZ4755_CLK_EXT_HALF, },
212 .gate = { CGU_REG_CLKGR, 15 },
213 },
214
215 [JZ4755_CLK_ADC] = {
216 "adc", CGU_CLK_GATE,
217 .parents = { JZ4755_CLK_EXT_HALF, },
218 .gate = { CGU_REG_CLKGR, 7 },
219 },
220
221 [JZ4755_CLK_AIC] = {
222 "aic", CGU_CLK_GATE,
223 .parents = { JZ4755_CLK_EXT_HALF, },
224 .gate = { CGU_REG_CLKGR, 5 },
225 },
226
227 [JZ4755_CLK_I2C] = {
228 "i2c", CGU_CLK_GATE,
229 .parents = { JZ4755_CLK_EXT_HALF, },
230 .gate = { CGU_REG_CLKGR, 3 },
231 },
232
233 [JZ4755_CLK_BCH] = {
234 "bch", CGU_CLK_GATE,
235 .parents = { JZ4755_CLK_H1CLK, },
236 .gate = { CGU_REG_CLKGR, 11 },
237 },
238
239 [JZ4755_CLK_TCU] = {
240 "tcu", CGU_CLK_GATE,
241 .parents = { JZ4755_CLK_EXT, },
242 .gate = { CGU_REG_CLKGR, 1 },
243 },
244
245 [JZ4755_CLK_DMA] = {
246 "dma", CGU_CLK_GATE,
247 .parents = { JZ4755_CLK_PCLK, },
248 .gate = { CGU_REG_CLKGR, 12 },
249 },
250
251 [JZ4755_CLK_MMC0] = {
252 "mmc0", CGU_CLK_GATE,
253 .parents = { JZ4755_CLK_MMC, },
254 .gate = { CGU_REG_CLKGR, 6 },
255 },
256
257 [JZ4755_CLK_MMC1] = {
258 "mmc1", CGU_CLK_GATE,
259 .parents = { JZ4755_CLK_MMC, },
260 .gate = { CGU_REG_CLKGR, 16 },
261 },
262
263 [JZ4755_CLK_AUX_CPU] = {
264 "aux_cpu", CGU_CLK_GATE,
265 .parents = { JZ4755_CLK_H1CLK, },
266 .gate = { CGU_REG_CLKGR, 24 },
267 },
268
269 [JZ4755_CLK_AHB1] = {
270 "ahb1", CGU_CLK_GATE,
271 .parents = { JZ4755_CLK_H1CLK, },
272 .gate = { CGU_REG_CLKGR, 23 },
273 },
274
275 [JZ4755_CLK_IDCT] = {
276 "idct", CGU_CLK_GATE,
277 .parents = { JZ4755_CLK_H1CLK, },
278 .gate = { CGU_REG_CLKGR, 22 },
279 },
280
281 [JZ4755_CLK_DB] = {
282 "db", CGU_CLK_GATE,
283 .parents = { JZ4755_CLK_H1CLK, },
284 .gate = { CGU_REG_CLKGR, 21 },
285 },
286
287 [JZ4755_CLK_ME] = {
288 "me", CGU_CLK_GATE,
289 .parents = { JZ4755_CLK_H1CLK, },
290 .gate = { CGU_REG_CLKGR, 20 },
291 },
292
293 [JZ4755_CLK_MC] = {
294 "mc", CGU_CLK_GATE,
295 .parents = { JZ4755_CLK_H1CLK, },
296 .gate = { CGU_REG_CLKGR, 19 },
297 },
298
299 [JZ4755_CLK_TSSI] = {
300 "tssi", CGU_CLK_GATE,
301 .parents = { JZ4755_CLK_EXT_HALF/* not sure */, },
302 .gate = { CGU_REG_CLKGR, 17 },
303 },
304
305 [JZ4755_CLK_IPU] = {
306 "ipu", CGU_CLK_GATE,
307 .parents = { JZ4755_CLK_PLL_HALF/* not sure */, },
308 .gate = { CGU_REG_CLKGR, 13 },
309 },
310
311 [JZ4755_CLK_EXT512] = {
312 "ext/512", CGU_CLK_FIXDIV,
313 .parents = { JZ4755_CLK_EXT, },
314
315 .fixdiv = { 512 },
316 },
317
318 [JZ4755_CLK_UDC_PHY] = {
319 "udc_phy", CGU_CLK_GATE,
320 .parents = { JZ4755_CLK_EXT_HALF, },
321 .gate = { CGU_REG_OPCR, 6, true },
322 },
323};
324
325static void __init jz4755_cgu_init(struct device_node *np)
326{
327 int retval;
328
329 cgu = ingenic_cgu_new(clock_info: jz4755_cgu_clocks,
330 ARRAY_SIZE(jz4755_cgu_clocks), np);
331 if (!cgu) {
332 pr_err("%s: failed to initialise CGU\n", __func__);
333 return;
334 }
335
336 retval = ingenic_cgu_register_clocks(cgu);
337 if (retval)
338 pr_err("%s: failed to register CGU Clocks\n", __func__);
339
340 ingenic_cgu_register_syscore_ops(cgu);
341}
342/*
343 * CGU has some children devices, this is useful for probing children devices
344 * in the case where the device node is compatible with "simple-mfd".
345 */
346CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu", jz4755_cgu_init);
347

source code of linux/drivers/clk/ingenic/jz4755-cgu.c