.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Ingenic JZ4740 SoC CGU driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015 Imagination Technologies |
---|
5 | 6 | * Author: Paul Burton <paul.burton@mips.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License as |
---|
9 | | - * published by the Free Software Foundation; either version 2 of |
---|
10 | | - * the License, or (at your option) any later version. |
---|
11 | | - * |
---|
12 | | - * This program is distributed in the hope that it will be useful, |
---|
13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | | - * GNU General Public License for more details. |
---|
16 | 7 | */ |
---|
17 | 8 | |
---|
18 | 9 | #include <linux/clk-provider.h> |
---|
19 | 10 | #include <linux/delay.h> |
---|
| 11 | +#include <linux/io.h> |
---|
20 | 12 | #include <linux/of.h> |
---|
| 13 | + |
---|
21 | 14 | #include <dt-bindings/clock/jz4740-cgu.h> |
---|
22 | | -#include <asm/mach-jz4740/clock.h> |
---|
| 15 | + |
---|
23 | 16 | #include "cgu.h" |
---|
| 17 | +#include "pm.h" |
---|
24 | 18 | |
---|
25 | 19 | /* CGU register offsets */ |
---|
26 | 20 | #define CGU_REG_CPCCR 0x00 |
---|
.. | .. |
---|
57 | 51 | 0x0, 0x1, -1, 0x3, |
---|
58 | 52 | }; |
---|
59 | 53 | |
---|
| 54 | +static const u8 jz4740_cgu_cpccr_div_table[] = { |
---|
| 55 | + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, |
---|
| 56 | +}; |
---|
| 57 | + |
---|
| 58 | +static const u8 jz4740_cgu_pll_half_div_table[] = { |
---|
| 59 | + 2, 1, |
---|
| 60 | +}; |
---|
| 61 | + |
---|
60 | 62 | static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { |
---|
61 | 63 | |
---|
62 | 64 | /* External clocks */ |
---|
.. | .. |
---|
69 | 71 | .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, |
---|
70 | 72 | .pll = { |
---|
71 | 73 | .reg = CGU_REG_CPPCR, |
---|
| 74 | + .rate_multiplier = 1, |
---|
72 | 75 | .m_shift = 23, |
---|
73 | 76 | .m_bits = 9, |
---|
74 | 77 | .m_offset = 2, |
---|
.. | .. |
---|
80 | 83 | .od_max = 4, |
---|
81 | 84 | .od_encoding = pll_od_encoding, |
---|
82 | 85 | .stable_bit = 10, |
---|
| 86 | + .bypass_reg = CGU_REG_CPPCR, |
---|
83 | 87 | .bypass_bit = 9, |
---|
84 | 88 | .enable_bit = 8, |
---|
85 | 89 | }, |
---|
.. | .. |
---|
90 | 94 | [JZ4740_CLK_PLL_HALF] = { |
---|
91 | 95 | "pll half", CGU_CLK_DIV, |
---|
92 | 96 | .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, |
---|
93 | | - .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 }, |
---|
| 97 | + .div = { |
---|
| 98 | + CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, |
---|
| 99 | + jz4740_cgu_pll_half_div_table, |
---|
| 100 | + }, |
---|
94 | 101 | }, |
---|
95 | 102 | |
---|
96 | 103 | [JZ4740_CLK_CCLK] = { |
---|
97 | 104 | "cclk", CGU_CLK_DIV, |
---|
98 | 105 | .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, |
---|
99 | | - .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, |
---|
| 106 | + .div = { |
---|
| 107 | + CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, |
---|
| 108 | + jz4740_cgu_cpccr_div_table, |
---|
| 109 | + }, |
---|
100 | 110 | }, |
---|
101 | 111 | |
---|
102 | 112 | [JZ4740_CLK_HCLK] = { |
---|
103 | 113 | "hclk", CGU_CLK_DIV, |
---|
104 | 114 | .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, |
---|
105 | | - .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, |
---|
| 115 | + .div = { |
---|
| 116 | + CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, |
---|
| 117 | + jz4740_cgu_cpccr_div_table, |
---|
| 118 | + }, |
---|
106 | 119 | }, |
---|
107 | 120 | |
---|
108 | 121 | [JZ4740_CLK_PCLK] = { |
---|
109 | 122 | "pclk", CGU_CLK_DIV, |
---|
110 | 123 | .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, |
---|
111 | | - .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 }, |
---|
| 124 | + .div = { |
---|
| 125 | + CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, |
---|
| 126 | + jz4740_cgu_cpccr_div_table, |
---|
| 127 | + }, |
---|
112 | 128 | }, |
---|
113 | 129 | |
---|
114 | 130 | [JZ4740_CLK_MCLK] = { |
---|
115 | 131 | "mclk", CGU_CLK_DIV, |
---|
116 | 132 | .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, |
---|
117 | | - .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, |
---|
| 133 | + .div = { |
---|
| 134 | + CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, |
---|
| 135 | + jz4740_cgu_cpccr_div_table, |
---|
| 136 | + }, |
---|
118 | 137 | }, |
---|
119 | 138 | |
---|
120 | 139 | [JZ4740_CLK_LCD] = { |
---|
121 | 140 | "lcd", CGU_CLK_DIV | CGU_CLK_GATE, |
---|
122 | 141 | .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, |
---|
123 | | - .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 }, |
---|
| 142 | + .div = { |
---|
| 143 | + CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1, |
---|
| 144 | + jz4740_cgu_cpccr_div_table, |
---|
| 145 | + }, |
---|
124 | 146 | .gate = { CGU_REG_CLKGR, 10 }, |
---|
125 | 147 | }, |
---|
126 | 148 | |
---|
.. | .. |
---|
211 | 233 | .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, |
---|
212 | 234 | .gate = { CGU_REG_CLKGR, 5 }, |
---|
213 | 235 | }, |
---|
| 236 | + |
---|
| 237 | + [JZ4740_CLK_TCU] = { |
---|
| 238 | + "tcu", CGU_CLK_GATE, |
---|
| 239 | + .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, |
---|
| 240 | + .gate = { CGU_REG_CLKGR, 1 }, |
---|
| 241 | + }, |
---|
214 | 242 | }; |
---|
215 | 243 | |
---|
216 | 244 | static void __init jz4740_cgu_init(struct device_node *np) |
---|
.. | .. |
---|
227 | 255 | retval = ingenic_cgu_register_clocks(cgu); |
---|
228 | 256 | if (retval) |
---|
229 | 257 | pr_err("%s: failed to register CGU Clocks\n", __func__); |
---|
| 258 | + |
---|
| 259 | + ingenic_cgu_register_syscore_ops(cgu); |
---|
230 | 260 | } |
---|
231 | | -CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init); |
---|
232 | | - |
---|
233 | | -void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode) |
---|
234 | | -{ |
---|
235 | | - uint32_t lcr = readl(cgu->base + CGU_REG_LCR); |
---|
236 | | - |
---|
237 | | - switch (mode) { |
---|
238 | | - case JZ4740_WAIT_MODE_IDLE: |
---|
239 | | - lcr &= ~LCR_SLEEP; |
---|
240 | | - break; |
---|
241 | | - |
---|
242 | | - case JZ4740_WAIT_MODE_SLEEP: |
---|
243 | | - lcr |= LCR_SLEEP; |
---|
244 | | - break; |
---|
245 | | - } |
---|
246 | | - |
---|
247 | | - writel(lcr, cgu->base + CGU_REG_LCR); |
---|
248 | | -} |
---|
249 | | - |
---|
250 | | -void jz4740_clock_udc_disable_auto_suspend(void) |
---|
251 | | -{ |
---|
252 | | - uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR); |
---|
253 | | - |
---|
254 | | - clkgr &= ~CLKGR_UDC; |
---|
255 | | - writel(clkgr, cgu->base + CGU_REG_CLKGR); |
---|
256 | | -} |
---|
257 | | -EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend); |
---|
258 | | - |
---|
259 | | -void jz4740_clock_udc_enable_auto_suspend(void) |
---|
260 | | -{ |
---|
261 | | - uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR); |
---|
262 | | - |
---|
263 | | - clkgr |= CLKGR_UDC; |
---|
264 | | - writel(clkgr, cgu->base + CGU_REG_CLKGR); |
---|
265 | | -} |
---|
266 | | -EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend); |
---|
267 | | - |
---|
268 | | -#define JZ_CLOCK_GATE_UART0 BIT(0) |
---|
269 | | -#define JZ_CLOCK_GATE_TCU BIT(1) |
---|
270 | | -#define JZ_CLOCK_GATE_DMAC BIT(12) |
---|
271 | | - |
---|
272 | | -void jz4740_clock_suspend(void) |
---|
273 | | -{ |
---|
274 | | - uint32_t clkgr, cppcr; |
---|
275 | | - |
---|
276 | | - clkgr = readl(cgu->base + CGU_REG_CLKGR); |
---|
277 | | - clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0; |
---|
278 | | - writel(clkgr, cgu->base + CGU_REG_CLKGR); |
---|
279 | | - |
---|
280 | | - cppcr = readl(cgu->base + CGU_REG_CPPCR); |
---|
281 | | - cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit); |
---|
282 | | - writel(cppcr, cgu->base + CGU_REG_CPPCR); |
---|
283 | | -} |
---|
284 | | - |
---|
285 | | -void jz4740_clock_resume(void) |
---|
286 | | -{ |
---|
287 | | - uint32_t clkgr, cppcr, stable; |
---|
288 | | - |
---|
289 | | - cppcr = readl(cgu->base + CGU_REG_CPPCR); |
---|
290 | | - cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit); |
---|
291 | | - writel(cppcr, cgu->base + CGU_REG_CPPCR); |
---|
292 | | - |
---|
293 | | - stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit); |
---|
294 | | - do { |
---|
295 | | - cppcr = readl(cgu->base + CGU_REG_CPPCR); |
---|
296 | | - } while (!(cppcr & stable)); |
---|
297 | | - |
---|
298 | | - clkgr = readl(cgu->base + CGU_REG_CLKGR); |
---|
299 | | - clkgr &= ~JZ_CLOCK_GATE_TCU; |
---|
300 | | - clkgr &= ~JZ_CLOCK_GATE_DMAC; |
---|
301 | | - clkgr &= ~JZ_CLOCK_GATE_UART0; |
---|
302 | | - writel(clkgr, cgu->base + CGU_REG_CLKGR); |
---|
303 | | -} |
---|
| 261 | +CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init); |
---|