Merge branch 'for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[sfrench/cifs-2.6.git] / drivers / clk / ingenic / jz4740-cgu.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Ingenic JZ4740 SoC CGU driver
4  *
5  * Copyright (c) 2015 Imagination Technologies
6  * Author: Paul Burton <paul.burton@mips.com>
7  */
8
9 #include <linux/clk-provider.h>
10 #include <linux/delay.h>
11 #include <linux/io.h>
12 #include <linux/of.h>
13 #include <dt-bindings/clock/jz4740-cgu.h>
14 #include <asm/mach-jz4740/clock.h>
15 #include "cgu.h"
16
17 /* CGU register offsets */
18 #define CGU_REG_CPCCR           0x00
19 #define CGU_REG_LCR             0x04
20 #define CGU_REG_CPPCR           0x10
21 #define CGU_REG_CLKGR           0x20
22 #define CGU_REG_SCR             0x24
23 #define CGU_REG_I2SCDR          0x60
24 #define CGU_REG_LPCDR           0x64
25 #define CGU_REG_MSCCDR          0x68
26 #define CGU_REG_UHCCDR          0x6c
27 #define CGU_REG_SSICDR          0x74
28
29 /* bits within a PLL control register */
30 #define PLLCTL_M_SHIFT          23
31 #define PLLCTL_M_MASK           (0x1ff << PLLCTL_M_SHIFT)
32 #define PLLCTL_N_SHIFT          18
33 #define PLLCTL_N_MASK           (0x1f << PLLCTL_N_SHIFT)
34 #define PLLCTL_OD_SHIFT         16
35 #define PLLCTL_OD_MASK          (0x3 << PLLCTL_OD_SHIFT)
36 #define PLLCTL_STABLE           (1 << 10)
37 #define PLLCTL_BYPASS           (1 << 9)
38 #define PLLCTL_ENABLE           (1 << 8)
39
40 /* bits within the LCR register */
41 #define LCR_SLEEP               (1 << 0)
42
43 /* bits within the CLKGR register */
44 #define CLKGR_UDC               (1 << 11)
45
46 static struct ingenic_cgu *cgu;
47
48 static const s8 pll_od_encoding[4] = {
49         0x0, 0x1, -1, 0x3,
50 };
51
52 static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
53
54         /* External clocks */
55
56         [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
57         [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
58
59         [JZ4740_CLK_PLL] = {
60                 "pll", CGU_CLK_PLL,
61                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
62                 .pll = {
63                         .reg = CGU_REG_CPPCR,
64                         .m_shift = 23,
65                         .m_bits = 9,
66                         .m_offset = 2,
67                         .n_shift = 18,
68                         .n_bits = 5,
69                         .n_offset = 2,
70                         .od_shift = 16,
71                         .od_bits = 2,
72                         .od_max = 4,
73                         .od_encoding = pll_od_encoding,
74                         .stable_bit = 10,
75                         .bypass_bit = 9,
76                         .enable_bit = 8,
77                 },
78         },
79
80         /* Muxes & dividers */
81
82         [JZ4740_CLK_PLL_HALF] = {
83                 "pll half", CGU_CLK_DIV,
84                 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
85                 .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
86         },
87
88         [JZ4740_CLK_CCLK] = {
89                 "cclk", CGU_CLK_DIV,
90                 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
91                 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
92         },
93
94         [JZ4740_CLK_HCLK] = {
95                 "hclk", CGU_CLK_DIV,
96                 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
97                 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
98         },
99
100         [JZ4740_CLK_PCLK] = {
101                 "pclk", CGU_CLK_DIV,
102                 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
103                 .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
104         },
105
106         [JZ4740_CLK_MCLK] = {
107                 "mclk", CGU_CLK_DIV,
108                 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
109                 .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
110         },
111
112         [JZ4740_CLK_LCD] = {
113                 "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
114                 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
115                 .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 },
116                 .gate = { CGU_REG_CLKGR, 10 },
117         },
118
119         [JZ4740_CLK_LCD_PCLK] = {
120                 "lcd_pclk", CGU_CLK_DIV,
121                 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
122                 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
123         },
124
125         [JZ4740_CLK_I2S] = {
126                 "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
127                 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
128                 .mux = { CGU_REG_CPCCR, 31, 1 },
129                 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
130                 .gate = { CGU_REG_CLKGR, 6 },
131         },
132
133         [JZ4740_CLK_SPI] = {
134                 "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
135                 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
136                 .mux = { CGU_REG_SSICDR, 31, 1 },
137                 .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
138                 .gate = { CGU_REG_CLKGR, 4 },
139         },
140
141         [JZ4740_CLK_MMC] = {
142                 "mmc", CGU_CLK_DIV | CGU_CLK_GATE,
143                 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
144                 .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
145                 .gate = { CGU_REG_CLKGR, 7 },
146         },
147
148         [JZ4740_CLK_UHC] = {
149                 "uhc", CGU_CLK_DIV | CGU_CLK_GATE,
150                 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
151                 .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
152                 .gate = { CGU_REG_CLKGR, 14 },
153         },
154
155         [JZ4740_CLK_UDC] = {
156                 "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
157                 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
158                 .mux = { CGU_REG_CPCCR, 29, 1 },
159                 .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
160                 .gate = { CGU_REG_SCR, 6, true },
161         },
162
163         /* Gate-only clocks */
164
165         [JZ4740_CLK_UART0] = {
166                 "uart0", CGU_CLK_GATE,
167                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
168                 .gate = { CGU_REG_CLKGR, 0 },
169         },
170
171         [JZ4740_CLK_UART1] = {
172                 "uart1", CGU_CLK_GATE,
173                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
174                 .gate = { CGU_REG_CLKGR, 15 },
175         },
176
177         [JZ4740_CLK_DMA] = {
178                 "dma", CGU_CLK_GATE,
179                 .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
180                 .gate = { CGU_REG_CLKGR, 12 },
181         },
182
183         [JZ4740_CLK_IPU] = {
184                 "ipu", CGU_CLK_GATE,
185                 .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
186                 .gate = { CGU_REG_CLKGR, 13 },
187         },
188
189         [JZ4740_CLK_ADC] = {
190                 "adc", CGU_CLK_GATE,
191                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
192                 .gate = { CGU_REG_CLKGR, 8 },
193         },
194
195         [JZ4740_CLK_I2C] = {
196                 "i2c", CGU_CLK_GATE,
197                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
198                 .gate = { CGU_REG_CLKGR, 3 },
199         },
200
201         [JZ4740_CLK_AIC] = {
202                 "aic", CGU_CLK_GATE,
203                 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
204                 .gate = { CGU_REG_CLKGR, 5 },
205         },
206 };
207
208 static void __init jz4740_cgu_init(struct device_node *np)
209 {
210         int retval;
211
212         cgu = ingenic_cgu_new(jz4740_cgu_clocks,
213                               ARRAY_SIZE(jz4740_cgu_clocks), np);
214         if (!cgu) {
215                 pr_err("%s: failed to initialise CGU\n", __func__);
216                 return;
217         }
218
219         retval = ingenic_cgu_register_clocks(cgu);
220         if (retval)
221                 pr_err("%s: failed to register CGU Clocks\n", __func__);
222 }
223 CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
224
225 void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
226 {
227         uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
228
229         switch (mode) {
230         case JZ4740_WAIT_MODE_IDLE:
231                 lcr &= ~LCR_SLEEP;
232                 break;
233
234         case JZ4740_WAIT_MODE_SLEEP:
235                 lcr |= LCR_SLEEP;
236                 break;
237         }
238
239         writel(lcr, cgu->base + CGU_REG_LCR);
240 }
241
242 void jz4740_clock_udc_disable_auto_suspend(void)
243 {
244         uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
245
246         clkgr &= ~CLKGR_UDC;
247         writel(clkgr, cgu->base + CGU_REG_CLKGR);
248 }
249 EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
250
251 void jz4740_clock_udc_enable_auto_suspend(void)
252 {
253         uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
254
255         clkgr |= CLKGR_UDC;
256         writel(clkgr, cgu->base + CGU_REG_CLKGR);
257 }
258 EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
259
260 #define JZ_CLOCK_GATE_UART0     BIT(0)
261 #define JZ_CLOCK_GATE_TCU       BIT(1)
262 #define JZ_CLOCK_GATE_DMAC      BIT(12)
263
264 void jz4740_clock_suspend(void)
265 {
266         uint32_t clkgr, cppcr;
267
268         clkgr = readl(cgu->base + CGU_REG_CLKGR);
269         clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
270         writel(clkgr, cgu->base + CGU_REG_CLKGR);
271
272         cppcr = readl(cgu->base + CGU_REG_CPPCR);
273         cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
274         writel(cppcr, cgu->base + CGU_REG_CPPCR);
275 }
276
277 void jz4740_clock_resume(void)
278 {
279         uint32_t clkgr, cppcr, stable;
280
281         cppcr = readl(cgu->base + CGU_REG_CPPCR);
282         cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
283         writel(cppcr, cgu->base + CGU_REG_CPPCR);
284
285         stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
286         do {
287                 cppcr = readl(cgu->base + CGU_REG_CPPCR);
288         } while (!(cppcr & stable));
289
290         clkgr = readl(cgu->base + CGU_REG_CLKGR);
291         clkgr &= ~JZ_CLOCK_GATE_TCU;
292         clkgr &= ~JZ_CLOCK_GATE_DMAC;
293         clkgr &= ~JZ_CLOCK_GATE_UART0;
294         writel(clkgr, cgu->base + CGU_REG_CLKGR);
295 }