1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * X1000 SoC CGU driver |
4 | * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> |
5 | */ |
6 | |
7 | #include <linux/clk-provider.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/io.h> |
10 | #include <linux/of.h> |
11 | #include <linux/rational.h> |
12 | |
13 | #include <dt-bindings/clock/ingenic,x1000-cgu.h> |
14 | |
15 | #include "cgu.h" |
16 | #include "pm.h" |
17 | |
18 | /* CGU register offsets */ |
19 | #define CGU_REG_CPCCR 0x00 |
20 | #define CGU_REG_APLL 0x10 |
21 | #define CGU_REG_MPLL 0x14 |
22 | #define CGU_REG_CLKGR 0x20 |
23 | #define CGU_REG_OPCR 0x24 |
24 | #define CGU_REG_DDRCDR 0x2c |
25 | #define CGU_REG_USBPCR 0x3c |
26 | #define CGU_REG_USBPCR1 0x48 |
27 | #define CGU_REG_USBCDR 0x50 |
28 | #define CGU_REG_MACCDR 0x54 |
29 | #define CGU_REG_I2SCDR 0x60 |
30 | #define CGU_REG_LPCDR 0x64 |
31 | #define CGU_REG_MSC0CDR 0x68 |
32 | #define CGU_REG_I2SCDR1 0x70 |
33 | #define CGU_REG_SSICDR 0x74 |
34 | #define CGU_REG_CIMCDR 0x7c |
35 | #define CGU_REG_PCMCDR 0x84 |
36 | #define CGU_REG_MSC1CDR 0xa4 |
37 | #define CGU_REG_CMP_INTR 0xb0 |
38 | #define CGU_REG_CMP_INTRE 0xb4 |
39 | #define CGU_REG_DRCG 0xd0 |
40 | #define CGU_REG_CPCSR 0xd4 |
41 | #define CGU_REG_PCMCDR1 0xe0 |
42 | #define CGU_REG_MACPHYC 0xe8 |
43 | |
44 | /* bits within the OPCR register */ |
45 | #define OPCR_SPENDN0 BIT(7) |
46 | #define OPCR_SPENDN1 BIT(6) |
47 | |
48 | /* bits within the USBPCR register */ |
49 | #define USBPCR_SIDDQ BIT(21) |
50 | #define USBPCR_OTG_DISABLE BIT(20) |
51 | |
52 | /* bits within the USBPCR1 register */ |
53 | #define USBPCR1_REFCLKSEL_SHIFT 26 |
54 | #define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT) |
55 | #define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT) |
56 | #define USBPCR1_REFCLKDIV_SHIFT 24 |
57 | #define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT) |
58 | #define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT) |
59 | #define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT) |
60 | #define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT) |
61 | |
62 | static struct ingenic_cgu *cgu; |
63 | |
64 | static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw, |
65 | unsigned long parent_rate) |
66 | { |
67 | u32 usbpcr1; |
68 | unsigned refclk_div; |
69 | |
70 | usbpcr1 = readl(addr: cgu->base + CGU_REG_USBPCR1); |
71 | refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK; |
72 | |
73 | switch (refclk_div) { |
74 | case USBPCR1_REFCLKDIV_12: |
75 | return 12000000; |
76 | |
77 | case USBPCR1_REFCLKDIV_24: |
78 | return 24000000; |
79 | |
80 | case USBPCR1_REFCLKDIV_48: |
81 | return 48000000; |
82 | } |
83 | |
84 | return parent_rate; |
85 | } |
86 | |
87 | static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate, |
88 | unsigned long *parent_rate) |
89 | { |
90 | if (req_rate < 18000000) |
91 | return 12000000; |
92 | |
93 | if (req_rate < 36000000) |
94 | return 24000000; |
95 | |
96 | return 48000000; |
97 | } |
98 | |
99 | static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, |
100 | unsigned long parent_rate) |
101 | { |
102 | unsigned long flags; |
103 | u32 usbpcr1, div_bits; |
104 | |
105 | switch (req_rate) { |
106 | case 12000000: |
107 | div_bits = USBPCR1_REFCLKDIV_12; |
108 | break; |
109 | |
110 | case 24000000: |
111 | div_bits = USBPCR1_REFCLKDIV_24; |
112 | break; |
113 | |
114 | case 48000000: |
115 | div_bits = USBPCR1_REFCLKDIV_48; |
116 | break; |
117 | |
118 | default: |
119 | return -EINVAL; |
120 | } |
121 | |
122 | spin_lock_irqsave(&cgu->lock, flags); |
123 | |
124 | usbpcr1 = readl(addr: cgu->base + CGU_REG_USBPCR1); |
125 | usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK; |
126 | usbpcr1 |= div_bits; |
127 | writel(val: usbpcr1, addr: cgu->base + CGU_REG_USBPCR1); |
128 | |
129 | spin_unlock_irqrestore(lock: &cgu->lock, flags); |
130 | return 0; |
131 | } |
132 | |
133 | static int x1000_usb_phy_enable(struct clk_hw *hw) |
134 | { |
135 | void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; |
136 | void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; |
137 | |
138 | writel(readl(addr: reg_opcr) | OPCR_SPENDN0, addr: reg_opcr); |
139 | writel(readl(addr: reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, addr: reg_usbpcr); |
140 | return 0; |
141 | } |
142 | |
143 | static void x1000_usb_phy_disable(struct clk_hw *hw) |
144 | { |
145 | void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; |
146 | void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; |
147 | |
148 | writel(readl(addr: reg_opcr) & ~OPCR_SPENDN0, addr: reg_opcr); |
149 | writel(readl(addr: reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, addr: reg_usbpcr); |
150 | } |
151 | |
152 | static int x1000_usb_phy_is_enabled(struct clk_hw *hw) |
153 | { |
154 | void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; |
155 | void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; |
156 | |
157 | return (readl(addr: reg_opcr) & OPCR_SPENDN0) && |
158 | !(readl(addr: reg_usbpcr) & USBPCR_SIDDQ) && |
159 | !(readl(addr: reg_usbpcr) & USBPCR_OTG_DISABLE); |
160 | } |
161 | |
162 | static const struct clk_ops x1000_otg_phy_ops = { |
163 | .recalc_rate = x1000_otg_phy_recalc_rate, |
164 | .round_rate = x1000_otg_phy_round_rate, |
165 | .set_rate = x1000_otg_phy_set_rate, |
166 | |
167 | .enable = x1000_usb_phy_enable, |
168 | .disable = x1000_usb_phy_disable, |
169 | .is_enabled = x1000_usb_phy_is_enabled, |
170 | }; |
171 | |
172 | static void |
173 | x1000_i2spll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, |
174 | unsigned long rate, unsigned long parent_rate, |
175 | unsigned int *pm, unsigned int *pn, unsigned int *pod) |
176 | { |
177 | const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0); |
178 | const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0); |
179 | unsigned long m, n; |
180 | |
181 | rational_best_approximation(given_numerator: rate, given_denominator: parent_rate, max_numerator: m_max, max_denominator: n_max, best_numerator: &m, best_denominator: &n); |
182 | |
183 | /* n should not be less than 2*m */ |
184 | if (n < 2 * m) |
185 | n = 2 * m; |
186 | |
187 | *pm = m; |
188 | *pn = n; |
189 | *pod = 1; |
190 | } |
191 | |
192 | static void |
193 | x1000_i2spll_set_rate_hook(const struct ingenic_cgu_pll_info *pll_info, |
194 | unsigned long rate, unsigned long parent_rate) |
195 | { |
196 | /* |
197 | * Writing 0 causes I2SCDR1.I2SDIV_D to be automatically recalculated |
198 | * based on the current value of I2SCDR.I2SDIV_N, which is needed for |
199 | * the divider to function correctly. |
200 | */ |
201 | writel(val: 0, addr: cgu->base + CGU_REG_I2SCDR1); |
202 | } |
203 | |
204 | static const s8 pll_od_encoding[8] = { |
205 | 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, |
206 | }; |
207 | |
208 | static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { |
209 | |
210 | /* External clocks */ |
211 | |
212 | [X1000_CLK_EXCLK] = { "ext" , CGU_CLK_EXT }, |
213 | [X1000_CLK_RTCLK] = { "rtc" , CGU_CLK_EXT }, |
214 | |
215 | /* PLLs */ |
216 | |
217 | [X1000_CLK_APLL] = { |
218 | "apll" , CGU_CLK_PLL, |
219 | .parents = { X1000_CLK_EXCLK }, |
220 | .pll = { |
221 | .reg = CGU_REG_APLL, |
222 | .rate_multiplier = 1, |
223 | .m_shift = 24, |
224 | .m_bits = 7, |
225 | .m_offset = 1, |
226 | .n_shift = 18, |
227 | .n_bits = 5, |
228 | .n_offset = 1, |
229 | .od_shift = 16, |
230 | .od_bits = 2, |
231 | .od_max = 8, |
232 | .od_encoding = pll_od_encoding, |
233 | .bypass_reg = CGU_REG_APLL, |
234 | .bypass_bit = 9, |
235 | .enable_bit = 8, |
236 | .stable_bit = 10, |
237 | }, |
238 | }, |
239 | |
240 | [X1000_CLK_MPLL] = { |
241 | "mpll" , CGU_CLK_PLL, |
242 | .parents = { X1000_CLK_EXCLK }, |
243 | .pll = { |
244 | .reg = CGU_REG_MPLL, |
245 | .rate_multiplier = 1, |
246 | .m_shift = 24, |
247 | .m_bits = 7, |
248 | .m_offset = 1, |
249 | .n_shift = 18, |
250 | .n_bits = 5, |
251 | .n_offset = 1, |
252 | .od_shift = 16, |
253 | .od_bits = 2, |
254 | .od_max = 8, |
255 | .od_encoding = pll_od_encoding, |
256 | .bypass_reg = CGU_REG_MPLL, |
257 | .bypass_bit = 6, |
258 | .enable_bit = 7, |
259 | .stable_bit = 0, |
260 | }, |
261 | }, |
262 | |
263 | /* Custom (SoC-specific) OTG PHY */ |
264 | |
265 | [X1000_CLK_OTGPHY] = { |
266 | "otg_phy" , CGU_CLK_CUSTOM, |
267 | .parents = { -1, -1, X1000_CLK_EXCLK, -1 }, |
268 | .custom = { &x1000_otg_phy_ops }, |
269 | }, |
270 | |
271 | /* Muxes & dividers */ |
272 | |
273 | [X1000_CLK_SCLKA] = { |
274 | "sclk_a" , CGU_CLK_MUX, |
275 | .parents = { -1, X1000_CLK_EXCLK, X1000_CLK_APLL, -1 }, |
276 | .mux = { CGU_REG_CPCCR, 30, 2 }, |
277 | }, |
278 | |
279 | [X1000_CLK_CPUMUX] = { |
280 | "cpu_mux" , CGU_CLK_MUX, |
281 | .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 }, |
282 | .mux = { CGU_REG_CPCCR, 28, 2 }, |
283 | }, |
284 | |
285 | [X1000_CLK_CPU] = { |
286 | "cpu" , CGU_CLK_DIV | CGU_CLK_GATE, |
287 | /* |
288 | * Disabling the CPU clock or any parent clocks will hang the |
289 | * system; mark it critical. |
290 | */ |
291 | .flags = CLK_IS_CRITICAL, |
292 | .parents = { X1000_CLK_CPUMUX }, |
293 | .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, |
294 | .gate = { CGU_REG_CLKGR, 30 }, |
295 | }, |
296 | |
297 | [X1000_CLK_L2CACHE] = { |
298 | "l2cache" , CGU_CLK_DIV, |
299 | /* |
300 | * The L2 cache clock is critical if caches are enabled and |
301 | * disabling it or any parent clocks will hang the system. |
302 | */ |
303 | .flags = CLK_IS_CRITICAL, |
304 | .parents = { X1000_CLK_CPUMUX }, |
305 | .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, |
306 | }, |
307 | |
308 | [X1000_CLK_AHB0] = { |
309 | "ahb0" , CGU_CLK_MUX | CGU_CLK_DIV, |
310 | .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 }, |
311 | .mux = { CGU_REG_CPCCR, 26, 2 }, |
312 | .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 }, |
313 | }, |
314 | |
315 | [X1000_CLK_AHB2PMUX] = { |
316 | "ahb2_apb_mux" , CGU_CLK_MUX, |
317 | .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 }, |
318 | .mux = { CGU_REG_CPCCR, 24, 2 }, |
319 | }, |
320 | |
321 | [X1000_CLK_AHB2] = { |
322 | "ahb2" , CGU_CLK_DIV, |
323 | .parents = { X1000_CLK_AHB2PMUX }, |
324 | .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 }, |
325 | }, |
326 | |
327 | [X1000_CLK_PCLK] = { |
328 | "pclk" , CGU_CLK_DIV | CGU_CLK_GATE, |
329 | .parents = { X1000_CLK_AHB2PMUX }, |
330 | .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 }, |
331 | .gate = { CGU_REG_CLKGR, 28 }, |
332 | }, |
333 | |
334 | [X1000_CLK_DDR] = { |
335 | "ddr" , CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, |
336 | /* |
337 | * Disabling DDR clock or its parents will render DRAM |
338 | * inaccessible; mark it critical. |
339 | */ |
340 | .flags = CLK_IS_CRITICAL, |
341 | .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 }, |
342 | .mux = { CGU_REG_DDRCDR, 30, 2 }, |
343 | .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, |
344 | .gate = { CGU_REG_CLKGR, 31 }, |
345 | }, |
346 | |
347 | [X1000_CLK_MAC] = { |
348 | "mac" , CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, |
349 | .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, |
350 | .mux = { CGU_REG_MACCDR, 31, 1 }, |
351 | .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 }, |
352 | .gate = { CGU_REG_CLKGR, 25 }, |
353 | }, |
354 | |
355 | [X1000_CLK_I2SPLLMUX] = { |
356 | "i2s_pll_mux" , CGU_CLK_MUX, |
357 | .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, |
358 | .mux = { CGU_REG_I2SCDR, 31, 1 }, |
359 | }, |
360 | |
361 | [X1000_CLK_I2SPLL] = { |
362 | "i2s_pll" , CGU_CLK_PLL, |
363 | .parents = { X1000_CLK_I2SPLLMUX }, |
364 | .pll = { |
365 | .reg = CGU_REG_I2SCDR, |
366 | .rate_multiplier = 1, |
367 | .m_shift = 13, |
368 | .m_bits = 9, |
369 | .n_shift = 0, |
370 | .n_bits = 13, |
371 | .calc_m_n_od = x1000_i2spll_calc_m_n_od, |
372 | .set_rate_hook = x1000_i2spll_set_rate_hook, |
373 | }, |
374 | }, |
375 | |
376 | [X1000_CLK_I2S] = { |
377 | "i2s" , CGU_CLK_MUX, |
378 | .parents = { X1000_CLK_EXCLK, -1, -1, X1000_CLK_I2SPLL }, |
379 | /* |
380 | * NOTE: the mux is at bit 30; bit 29 enables the M/N divider. |
381 | * Therefore, the divider is disabled when EXCLK is selected. |
382 | */ |
383 | .mux = { CGU_REG_I2SCDR, 29, 2 }, |
384 | }, |
385 | |
386 | [X1000_CLK_LCD] = { |
387 | "lcd" , CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, |
388 | .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, |
389 | .mux = { CGU_REG_LPCDR, 31, 1 }, |
390 | .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 }, |
391 | .gate = { CGU_REG_CLKGR, 23 }, |
392 | }, |
393 | |
394 | [X1000_CLK_MSCMUX] = { |
395 | "msc_mux" , CGU_CLK_MUX, |
396 | .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, |
397 | .mux = { CGU_REG_MSC0CDR, 31, 1 }, |
398 | }, |
399 | |
400 | [X1000_CLK_MSC0] = { |
401 | "msc0" , CGU_CLK_DIV | CGU_CLK_GATE, |
402 | .parents = { X1000_CLK_MSCMUX }, |
403 | .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, |
404 | .gate = { CGU_REG_CLKGR, 4 }, |
405 | }, |
406 | |
407 | [X1000_CLK_MSC1] = { |
408 | "msc1" , CGU_CLK_DIV | CGU_CLK_GATE, |
409 | .parents = { X1000_CLK_MSCMUX, -1, -1, -1 }, |
410 | .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, |
411 | .gate = { CGU_REG_CLKGR, 5 }, |
412 | }, |
413 | |
414 | [X1000_CLK_OTG] = { |
415 | "otg" , CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, |
416 | .parents = { X1000_CLK_EXCLK, -1, X1000_CLK_APLL, X1000_CLK_MPLL }, |
417 | .mux = { CGU_REG_USBCDR, 30, 2 }, |
418 | .div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 }, |
419 | .gate = { CGU_REG_CLKGR, 3 }, |
420 | }, |
421 | |
422 | [X1000_CLK_SSIPLL] = { |
423 | "ssi_pll" , CGU_CLK_MUX | CGU_CLK_DIV, |
424 | .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, |
425 | .mux = { CGU_REG_SSICDR, 31, 1 }, |
426 | .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 }, |
427 | }, |
428 | |
429 | [X1000_CLK_SSIPLL_DIV2] = { |
430 | "ssi_pll_div2" , CGU_CLK_FIXDIV, |
431 | .parents = { X1000_CLK_SSIPLL }, |
432 | .fixdiv = { 2 }, |
433 | }, |
434 | |
435 | [X1000_CLK_SSIMUX] = { |
436 | "ssi_mux" , CGU_CLK_MUX, |
437 | .parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2 }, |
438 | .mux = { CGU_REG_SSICDR, 30, 1 }, |
439 | }, |
440 | |
441 | [X1000_CLK_EXCLK_DIV512] = { |
442 | "exclk_div512" , CGU_CLK_FIXDIV, |
443 | .parents = { X1000_CLK_EXCLK }, |
444 | .fixdiv = { 512 }, |
445 | }, |
446 | |
447 | [X1000_CLK_RTC] = { |
448 | "rtc_ercs" , CGU_CLK_MUX | CGU_CLK_GATE, |
449 | .parents = { X1000_CLK_EXCLK_DIV512, X1000_CLK_RTCLK }, |
450 | .mux = { CGU_REG_OPCR, 2, 1}, |
451 | .gate = { CGU_REG_CLKGR, 27 }, |
452 | }, |
453 | |
454 | /* Gate-only clocks */ |
455 | |
456 | [X1000_CLK_EMC] = { |
457 | "emc" , CGU_CLK_GATE, |
458 | .parents = { X1000_CLK_AHB2 }, |
459 | .gate = { CGU_REG_CLKGR, 0 }, |
460 | }, |
461 | |
462 | [X1000_CLK_EFUSE] = { |
463 | "efuse" , CGU_CLK_GATE, |
464 | .parents = { X1000_CLK_AHB2 }, |
465 | .gate = { CGU_REG_CLKGR, 1 }, |
466 | }, |
467 | |
468 | [X1000_CLK_SFC] = { |
469 | "sfc" , CGU_CLK_GATE, |
470 | .parents = { X1000_CLK_SSIPLL }, |
471 | .gate = { CGU_REG_CLKGR, 2 }, |
472 | }, |
473 | |
474 | [X1000_CLK_I2C0] = { |
475 | "i2c0" , CGU_CLK_GATE, |
476 | .parents = { X1000_CLK_PCLK }, |
477 | .gate = { CGU_REG_CLKGR, 7 }, |
478 | }, |
479 | |
480 | [X1000_CLK_I2C1] = { |
481 | "i2c1" , CGU_CLK_GATE, |
482 | .parents = { X1000_CLK_PCLK }, |
483 | .gate = { CGU_REG_CLKGR, 8 }, |
484 | }, |
485 | |
486 | [X1000_CLK_I2C2] = { |
487 | "i2c2" , CGU_CLK_GATE, |
488 | .parents = { X1000_CLK_PCLK }, |
489 | .gate = { CGU_REG_CLKGR, 9 }, |
490 | }, |
491 | |
492 | [X1000_CLK_AIC] = { |
493 | "aic" , CGU_CLK_GATE, |
494 | .parents = { X1000_CLK_EXCLK }, |
495 | .gate = { CGU_REG_CLKGR, 11 }, |
496 | }, |
497 | |
498 | [X1000_CLK_UART0] = { |
499 | "uart0" , CGU_CLK_GATE, |
500 | .parents = { X1000_CLK_EXCLK }, |
501 | .gate = { CGU_REG_CLKGR, 14 }, |
502 | }, |
503 | |
504 | [X1000_CLK_UART1] = { |
505 | "uart1" , CGU_CLK_GATE, |
506 | .parents = { X1000_CLK_EXCLK}, |
507 | .gate = { CGU_REG_CLKGR, 15 }, |
508 | }, |
509 | |
510 | [X1000_CLK_UART2] = { |
511 | "uart2" , CGU_CLK_GATE, |
512 | .parents = { X1000_CLK_EXCLK }, |
513 | .gate = { CGU_REG_CLKGR, 16 }, |
514 | }, |
515 | |
516 | [X1000_CLK_TCU] = { |
517 | "tcu" , CGU_CLK_GATE, |
518 | .parents = { X1000_CLK_EXCLK }, |
519 | .gate = { CGU_REG_CLKGR, 18 }, |
520 | }, |
521 | |
522 | [X1000_CLK_SSI] = { |
523 | "ssi" , CGU_CLK_GATE, |
524 | .parents = { X1000_CLK_SSIMUX }, |
525 | .gate = { CGU_REG_CLKGR, 19 }, |
526 | }, |
527 | |
528 | [X1000_CLK_OST] = { |
529 | "ost" , CGU_CLK_GATE, |
530 | .parents = { X1000_CLK_EXCLK }, |
531 | .gate = { CGU_REG_CLKGR, 20 }, |
532 | }, |
533 | |
534 | [X1000_CLK_PDMA] = { |
535 | "pdma" , CGU_CLK_GATE, |
536 | .parents = { X1000_CLK_EXCLK }, |
537 | .gate = { CGU_REG_CLKGR, 21 }, |
538 | }, |
539 | }; |
540 | |
541 | static void __init x1000_cgu_init(struct device_node *np) |
542 | { |
543 | int retval; |
544 | |
545 | cgu = ingenic_cgu_new(clock_info: x1000_cgu_clocks, |
546 | ARRAY_SIZE(x1000_cgu_clocks), np); |
547 | if (!cgu) { |
548 | pr_err("%s: failed to initialise CGU\n" , __func__); |
549 | return; |
550 | } |
551 | |
552 | retval = ingenic_cgu_register_clocks(cgu); |
553 | if (retval) { |
554 | pr_err("%s: failed to register CGU Clocks\n" , __func__); |
555 | return; |
556 | } |
557 | |
558 | ingenic_cgu_register_syscore_ops(cgu); |
559 | } |
560 | /* |
561 | * CGU has some children devices, this is useful for probing children devices |
562 | * in the case where the device node is compatible with "simple-mfd". |
563 | */ |
564 | CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-cgu" , x1000_cgu_init); |
565 | |