xref: /linux/drivers/clk/ingenic/jz4760-cgu.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1bdbfc029SPaul Cercueil // SPDX-License-Identifier: GPL-2.0
2bdbfc029SPaul Cercueil /*
3bdbfc029SPaul Cercueil  * JZ4760 SoC CGU driver
4bdbfc029SPaul Cercueil  * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
5bdbfc029SPaul Cercueil  */
6bdbfc029SPaul Cercueil 
7bdbfc029SPaul Cercueil #include <linux/bitops.h>
8bdbfc029SPaul Cercueil #include <linux/clk-provider.h>
9bdbfc029SPaul Cercueil #include <linux/delay.h>
10bdbfc029SPaul Cercueil #include <linux/io.h>
11bdbfc029SPaul Cercueil #include <linux/of.h>
12bdbfc029SPaul Cercueil 
13bdbfc029SPaul Cercueil #include <linux/clk.h>
14bdbfc029SPaul Cercueil 
15c4a11bf4SPaul Cercueil #include <dt-bindings/clock/ingenic,jz4760-cgu.h>
16bdbfc029SPaul Cercueil 
17bdbfc029SPaul Cercueil #include "cgu.h"
18bdbfc029SPaul Cercueil #include "pm.h"
19bdbfc029SPaul Cercueil 
20bdbfc029SPaul Cercueil #define MHZ (1000 * 1000)
21bdbfc029SPaul Cercueil 
22bdbfc029SPaul Cercueil /*
23bdbfc029SPaul Cercueil  * CPM registers offset address definition
24bdbfc029SPaul Cercueil  */
25bdbfc029SPaul Cercueil #define CGU_REG_CPCCR		0x00
26bdbfc029SPaul Cercueil #define CGU_REG_LCR		0x04
27bdbfc029SPaul Cercueil #define CGU_REG_CPPCR0		0x10
28bdbfc029SPaul Cercueil #define CGU_REG_CLKGR0		0x20
29bdbfc029SPaul Cercueil #define CGU_REG_OPCR		0x24
30bdbfc029SPaul Cercueil #define CGU_REG_CLKGR1		0x28
31bdbfc029SPaul Cercueil #define CGU_REG_CPPCR1		0x30
32bdbfc029SPaul Cercueil #define CGU_REG_USBPCR		0x3c
33bdbfc029SPaul Cercueil #define CGU_REG_USBCDR		0x50
34bdbfc029SPaul Cercueil #define CGU_REG_I2SCDR		0x60
35bdbfc029SPaul Cercueil #define CGU_REG_LPCDR		0x64
36bdbfc029SPaul Cercueil #define CGU_REG_MSCCDR		0x68
37bdbfc029SPaul Cercueil #define CGU_REG_UHCCDR		0x6c
38bdbfc029SPaul Cercueil #define CGU_REG_SSICDR		0x74
39bdbfc029SPaul Cercueil #define CGU_REG_CIMCDR		0x7c
40bdbfc029SPaul Cercueil #define CGU_REG_GPSCDR		0x80
41bdbfc029SPaul Cercueil #define CGU_REG_PCMCDR		0x84
42bdbfc029SPaul Cercueil #define CGU_REG_GPUCDR		0x88
43bdbfc029SPaul Cercueil 
44bdbfc029SPaul Cercueil static const s8 pll_od_encoding[8] = {
45bdbfc029SPaul Cercueil 	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
46bdbfc029SPaul Cercueil };
47bdbfc029SPaul Cercueil 
48bdbfc029SPaul Cercueil static const u8 jz4760_cgu_cpccr_div_table[] = {
49bdbfc029SPaul Cercueil 	1, 2, 3, 4, 6, 8,
50bdbfc029SPaul Cercueil };
51bdbfc029SPaul Cercueil 
52bdbfc029SPaul Cercueil static const u8 jz4760_cgu_pll_half_div_table[] = {
53bdbfc029SPaul Cercueil 	2, 1,
54bdbfc029SPaul Cercueil };
55bdbfc029SPaul Cercueil 
56bdbfc029SPaul Cercueil static void
jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info * pll_info,unsigned long rate,unsigned long parent_rate,unsigned int * pm,unsigned int * pn,unsigned int * pod)57bdbfc029SPaul Cercueil jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
58bdbfc029SPaul Cercueil 		       unsigned long rate, unsigned long parent_rate,
59bdbfc029SPaul Cercueil 		       unsigned int *pm, unsigned int *pn, unsigned int *pod)
60bdbfc029SPaul Cercueil {
61*ecfb9f40SPaul Cercueil 	unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1;
62bdbfc029SPaul Cercueil 
63bdbfc029SPaul Cercueil 	/* The frequency after the N divider must be between 1 and 50 MHz. */
64bdbfc029SPaul Cercueil 	n = parent_rate / (1 * MHZ);
65bdbfc029SPaul Cercueil 
66bdbfc029SPaul Cercueil 	/* The N divider must be >= 2. */
67bdbfc029SPaul Cercueil 	n = clamp_val(n, 2, 1 << pll_info->n_bits);
68bdbfc029SPaul Cercueil 
69*ecfb9f40SPaul Cercueil 	rate /= MHZ;
70*ecfb9f40SPaul Cercueil 	parent_rate /= MHZ;
71bdbfc029SPaul Cercueil 
72*ecfb9f40SPaul Cercueil 	for (m = m_max; m >= m_max && n >= 2; n--) {
73*ecfb9f40SPaul Cercueil 		m = rate * n / parent_rate;
74*ecfb9f40SPaul Cercueil 		od = m & 1;
75*ecfb9f40SPaul Cercueil 		m <<= od;
76bdbfc029SPaul Cercueil 	}
77bdbfc029SPaul Cercueil 
78bdbfc029SPaul Cercueil 	*pm = m;
79*ecfb9f40SPaul Cercueil 	*pn = n + 1;
80bdbfc029SPaul Cercueil 	*pod = 1 << od;
81bdbfc029SPaul Cercueil }
82bdbfc029SPaul Cercueil 
83bdbfc029SPaul Cercueil static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
84bdbfc029SPaul Cercueil 
85bdbfc029SPaul Cercueil 	/* External clocks */
86bdbfc029SPaul Cercueil 
87bdbfc029SPaul Cercueil 	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
88bdbfc029SPaul Cercueil 	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
89bdbfc029SPaul Cercueil 
90bdbfc029SPaul Cercueil 	/* PLLs */
91bdbfc029SPaul Cercueil 
92bdbfc029SPaul Cercueil 	[JZ4760_CLK_PLL0] = {
93bdbfc029SPaul Cercueil 		"pll0", CGU_CLK_PLL,
94bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT },
95bdbfc029SPaul Cercueil 		.pll = {
96bdbfc029SPaul Cercueil 			.reg = CGU_REG_CPPCR0,
97bdbfc029SPaul Cercueil 			.rate_multiplier = 1,
98bdbfc029SPaul Cercueil 			.m_shift = 23,
99bdbfc029SPaul Cercueil 			.m_bits = 8,
100bdbfc029SPaul Cercueil 			.m_offset = 0,
101bdbfc029SPaul Cercueil 			.n_shift = 18,
102bdbfc029SPaul Cercueil 			.n_bits = 4,
103bdbfc029SPaul Cercueil 			.n_offset = 0,
104bdbfc029SPaul Cercueil 			.od_shift = 16,
105bdbfc029SPaul Cercueil 			.od_bits = 2,
106bdbfc029SPaul Cercueil 			.od_max = 8,
107bdbfc029SPaul Cercueil 			.od_encoding = pll_od_encoding,
108bdbfc029SPaul Cercueil 			.bypass_reg = CGU_REG_CPPCR0,
109bdbfc029SPaul Cercueil 			.bypass_bit = 9,
110bdbfc029SPaul Cercueil 			.enable_bit = 8,
111bdbfc029SPaul Cercueil 			.stable_bit = 10,
112bdbfc029SPaul Cercueil 			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
113bdbfc029SPaul Cercueil 		},
114bdbfc029SPaul Cercueil 	},
115bdbfc029SPaul Cercueil 
116bdbfc029SPaul Cercueil 	[JZ4760_CLK_PLL1] = {
117bdbfc029SPaul Cercueil 		/* TODO: PLL1 can depend on PLL0 */
118bdbfc029SPaul Cercueil 		"pll1", CGU_CLK_PLL,
119bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT },
120bdbfc029SPaul Cercueil 		.pll = {
121bdbfc029SPaul Cercueil 			.reg = CGU_REG_CPPCR1,
122bdbfc029SPaul Cercueil 			.rate_multiplier = 1,
123bdbfc029SPaul Cercueil 			.m_shift = 23,
124bdbfc029SPaul Cercueil 			.m_bits = 8,
125bdbfc029SPaul Cercueil 			.m_offset = 0,
126bdbfc029SPaul Cercueil 			.n_shift = 18,
127bdbfc029SPaul Cercueil 			.n_bits = 4,
128bdbfc029SPaul Cercueil 			.n_offset = 0,
129bdbfc029SPaul Cercueil 			.od_shift = 16,
130bdbfc029SPaul Cercueil 			.od_bits = 2,
131bdbfc029SPaul Cercueil 			.od_max = 8,
132bdbfc029SPaul Cercueil 			.od_encoding = pll_od_encoding,
133bdbfc029SPaul Cercueil 			.bypass_bit = -1,
134bdbfc029SPaul Cercueil 			.enable_bit = 7,
135bdbfc029SPaul Cercueil 			.stable_bit = 6,
136bdbfc029SPaul Cercueil 			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
137bdbfc029SPaul Cercueil 		},
138bdbfc029SPaul Cercueil 	},
139bdbfc029SPaul Cercueil 
140bdbfc029SPaul Cercueil 	/* Main clocks */
141bdbfc029SPaul Cercueil 
142bdbfc029SPaul Cercueil 	[JZ4760_CLK_CCLK] = {
143bdbfc029SPaul Cercueil 		"cclk", CGU_CLK_DIV,
144ca54d06fSAidan MacDonald 		/*
145ca54d06fSAidan MacDonald 		 * Disabling the CPU clock or any parent clocks will hang the
146ca54d06fSAidan MacDonald 		 * system; mark it critical.
147ca54d06fSAidan MacDonald 		 */
148ca54d06fSAidan MacDonald 		.flags = CLK_IS_CRITICAL,
149bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
150bdbfc029SPaul Cercueil 		.div = {
151bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
152bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
153bdbfc029SPaul Cercueil 		},
154bdbfc029SPaul Cercueil 	},
155bdbfc029SPaul Cercueil 	[JZ4760_CLK_HCLK] = {
156bdbfc029SPaul Cercueil 		"hclk", CGU_CLK_DIV,
157bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
158bdbfc029SPaul Cercueil 		.div = {
159bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
160bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
161bdbfc029SPaul Cercueil 		},
162bdbfc029SPaul Cercueil 	},
163bdbfc029SPaul Cercueil 	[JZ4760_CLK_SCLK] = {
164bdbfc029SPaul Cercueil 		"sclk", CGU_CLK_DIV,
165bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
166bdbfc029SPaul Cercueil 		.div = {
167bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
168bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
169bdbfc029SPaul Cercueil 		},
170bdbfc029SPaul Cercueil 	},
171bdbfc029SPaul Cercueil 	[JZ4760_CLK_H2CLK] = {
172bdbfc029SPaul Cercueil 		"h2clk", CGU_CLK_DIV,
173bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
174bdbfc029SPaul Cercueil 		.div = {
175bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
176bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
177bdbfc029SPaul Cercueil 		},
178bdbfc029SPaul Cercueil 	},
179bdbfc029SPaul Cercueil 	[JZ4760_CLK_MCLK] = {
180bdbfc029SPaul Cercueil 		"mclk", CGU_CLK_DIV,
181ca54d06fSAidan MacDonald 		/*
182ca54d06fSAidan MacDonald 		 * Disabling MCLK or its parents will render DRAM
183ca54d06fSAidan MacDonald 		 * inaccessible; mark it critical.
184ca54d06fSAidan MacDonald 		 */
185ca54d06fSAidan MacDonald 		.flags = CLK_IS_CRITICAL,
186bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
187bdbfc029SPaul Cercueil 		.div = {
188bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
189bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
190bdbfc029SPaul Cercueil 		},
191bdbfc029SPaul Cercueil 	},
192bdbfc029SPaul Cercueil 	[JZ4760_CLK_PCLK] = {
193bdbfc029SPaul Cercueil 		"pclk", CGU_CLK_DIV,
194bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0, },
195bdbfc029SPaul Cercueil 		.div = {
196bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
197bdbfc029SPaul Cercueil 			jz4760_cgu_cpccr_div_table,
198bdbfc029SPaul Cercueil 		},
199bdbfc029SPaul Cercueil 	},
200bdbfc029SPaul Cercueil 
201bdbfc029SPaul Cercueil 	/* Divided clocks */
202bdbfc029SPaul Cercueil 
203bdbfc029SPaul Cercueil 	[JZ4760_CLK_PLL0_HALF] = {
204bdbfc029SPaul Cercueil 		"pll0_half", CGU_CLK_DIV,
205bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0 },
206bdbfc029SPaul Cercueil 		.div = {
207bdbfc029SPaul Cercueil 			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
208bdbfc029SPaul Cercueil 			jz4760_cgu_pll_half_div_table,
209bdbfc029SPaul Cercueil 		},
210bdbfc029SPaul Cercueil 	},
211bdbfc029SPaul Cercueil 
212bdbfc029SPaul Cercueil 	/* Those divided clocks can connect to PLL0 or PLL1 */
213bdbfc029SPaul Cercueil 
214bdbfc029SPaul Cercueil 	[JZ4760_CLK_UHC] = {
215bdbfc029SPaul Cercueil 		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
216bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
217bdbfc029SPaul Cercueil 		.mux = { CGU_REG_UHCCDR, 31, 1 },
218bdbfc029SPaul Cercueil 		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
219bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 24 },
220bdbfc029SPaul Cercueil 	},
221bdbfc029SPaul Cercueil 	[JZ4760_CLK_GPU] = {
222bdbfc029SPaul Cercueil 		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
223bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
224bdbfc029SPaul Cercueil 		.mux = { CGU_REG_GPUCDR, 31, 1 },
225bdbfc029SPaul Cercueil 		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
226bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 9 },
227bdbfc029SPaul Cercueil 	},
228bdbfc029SPaul Cercueil 	[JZ4760_CLK_LPCLK_DIV] = {
229bdbfc029SPaul Cercueil 		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
230bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
231bdbfc029SPaul Cercueil 		.mux = { CGU_REG_LPCDR, 29, 1 },
232bdbfc029SPaul Cercueil 		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
233bdbfc029SPaul Cercueil 	},
234bdbfc029SPaul Cercueil 	[JZ4760_CLK_TVE] = {
235bdbfc029SPaul Cercueil 		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
236bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
237bdbfc029SPaul Cercueil 		.mux = { CGU_REG_LPCDR, 31, 1 },
238bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 27 },
239bdbfc029SPaul Cercueil 	},
240bdbfc029SPaul Cercueil 	[JZ4760_CLK_LPCLK] = {
241bdbfc029SPaul Cercueil 		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
242bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
243bdbfc029SPaul Cercueil 		.mux = { CGU_REG_LPCDR, 30, 1 },
244bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 28 },
245bdbfc029SPaul Cercueil 	},
246bdbfc029SPaul Cercueil 	[JZ4760_CLK_GPS] = {
247bdbfc029SPaul Cercueil 		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
248bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
249bdbfc029SPaul Cercueil 		.mux = { CGU_REG_GPSCDR, 31, 1 },
250bdbfc029SPaul Cercueil 		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
251bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 22 },
252bdbfc029SPaul Cercueil 	},
253bdbfc029SPaul Cercueil 
254bdbfc029SPaul Cercueil 	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
255bdbfc029SPaul Cercueil 
256bdbfc029SPaul Cercueil 	[JZ4760_CLK_PCM] = {
257bdbfc029SPaul Cercueil 		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
258bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, -1,
259bdbfc029SPaul Cercueil 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
260bdbfc029SPaul Cercueil 		.mux = { CGU_REG_PCMCDR, 30, 2 },
261bdbfc029SPaul Cercueil 		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
262bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 8 },
263bdbfc029SPaul Cercueil 	},
264bdbfc029SPaul Cercueil 	[JZ4760_CLK_I2S] = {
265bdbfc029SPaul Cercueil 		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
266bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, -1,
267bdbfc029SPaul Cercueil 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
268bdbfc029SPaul Cercueil 		.mux = { CGU_REG_I2SCDR, 30, 2 },
269bdbfc029SPaul Cercueil 		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
270bdbfc029SPaul Cercueil 	},
271bdbfc029SPaul Cercueil 	[JZ4760_CLK_OTG] = {
272bdbfc029SPaul Cercueil 		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
273bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, -1,
274bdbfc029SPaul Cercueil 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
275bdbfc029SPaul Cercueil 		.mux = { CGU_REG_USBCDR, 30, 2 },
276bdbfc029SPaul Cercueil 		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
277bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 2 },
278bdbfc029SPaul Cercueil 	},
279bdbfc029SPaul Cercueil 
280bdbfc029SPaul Cercueil 	/* Those divided clocks can connect to EXT or PLL0 */
281bdbfc029SPaul Cercueil 	[JZ4760_CLK_MMC_MUX] = {
282bdbfc029SPaul Cercueil 		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
283bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
284bdbfc029SPaul Cercueil 		.mux = { CGU_REG_MSCCDR, 31, 1 },
285bdbfc029SPaul Cercueil 		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
286bdbfc029SPaul Cercueil 	},
287bdbfc029SPaul Cercueil 	[JZ4760_CLK_SSI_MUX] = {
288bdbfc029SPaul Cercueil 		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
289bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
290bdbfc029SPaul Cercueil 		.mux = { CGU_REG_SSICDR, 31, 1 },
291bdbfc029SPaul Cercueil 		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
292bdbfc029SPaul Cercueil 	},
293bdbfc029SPaul Cercueil 
294bdbfc029SPaul Cercueil 	/* These divided clock can connect to PLL0 only */
295bdbfc029SPaul Cercueil 	[JZ4760_CLK_CIM] = {
296bdbfc029SPaul Cercueil 		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
297bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_PLL0_HALF },
298bdbfc029SPaul Cercueil 		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
299bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 26 },
300bdbfc029SPaul Cercueil 	},
301bdbfc029SPaul Cercueil 
302bdbfc029SPaul Cercueil 	/* Gate-only clocks */
303bdbfc029SPaul Cercueil 
304bdbfc029SPaul Cercueil 	[JZ4760_CLK_SSI0] = {
305bdbfc029SPaul Cercueil 		"ssi0", CGU_CLK_GATE,
306bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_SSI_MUX, },
307bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 4 },
308bdbfc029SPaul Cercueil 	},
309bdbfc029SPaul Cercueil 	[JZ4760_CLK_SSI1] = {
310bdbfc029SPaul Cercueil 		"ssi1", CGU_CLK_GATE,
311bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_SSI_MUX, },
312bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 19 },
313bdbfc029SPaul Cercueil 	},
314bdbfc029SPaul Cercueil 	[JZ4760_CLK_SSI2] = {
315bdbfc029SPaul Cercueil 		"ssi2", CGU_CLK_GATE,
316bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_SSI_MUX, },
317bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 20 },
318bdbfc029SPaul Cercueil 	},
319bdbfc029SPaul Cercueil 	[JZ4760_CLK_DMA] = {
320bdbfc029SPaul Cercueil 		"dma", CGU_CLK_GATE,
321bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_H2CLK, },
322bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 21 },
323bdbfc029SPaul Cercueil 	},
324b5bc83bbSPaul Cercueil 	[JZ4760_CLK_MDMA] = {
325b5bc83bbSPaul Cercueil 		"mdma", CGU_CLK_GATE,
326b5bc83bbSPaul Cercueil 		.parents = { JZ4760_CLK_HCLK, },
327b5bc83bbSPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 25 },
328b5bc83bbSPaul Cercueil 	},
329b5bc83bbSPaul Cercueil 	[JZ4760_CLK_BDMA] = {
330b5bc83bbSPaul Cercueil 		"bdma", CGU_CLK_GATE,
331b5bc83bbSPaul Cercueil 		.parents = { JZ4760_CLK_HCLK, },
332b5bc83bbSPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 0 },
333b5bc83bbSPaul Cercueil 	},
334bdbfc029SPaul Cercueil 	[JZ4760_CLK_I2C0] = {
335bdbfc029SPaul Cercueil 		"i2c0", CGU_CLK_GATE,
336bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
337bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 5 },
338bdbfc029SPaul Cercueil 	},
339bdbfc029SPaul Cercueil 	[JZ4760_CLK_I2C1] = {
340bdbfc029SPaul Cercueil 		"i2c1", CGU_CLK_GATE,
341bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
342bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 6 },
343bdbfc029SPaul Cercueil 	},
344bdbfc029SPaul Cercueil 	[JZ4760_CLK_UART0] = {
345bdbfc029SPaul Cercueil 		"uart0", CGU_CLK_GATE,
346bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
347bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 15 },
348bdbfc029SPaul Cercueil 	},
349bdbfc029SPaul Cercueil 	[JZ4760_CLK_UART1] = {
350bdbfc029SPaul Cercueil 		"uart1", CGU_CLK_GATE,
351bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
352bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 16 },
353bdbfc029SPaul Cercueil 	},
354bdbfc029SPaul Cercueil 	[JZ4760_CLK_UART2] = {
355bdbfc029SPaul Cercueil 		"uart2", CGU_CLK_GATE,
356bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
357bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 17 },
358bdbfc029SPaul Cercueil 	},
359bdbfc029SPaul Cercueil 	[JZ4760_CLK_UART3] = {
360bdbfc029SPaul Cercueil 		"uart3", CGU_CLK_GATE,
361bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
362bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 18 },
363bdbfc029SPaul Cercueil 	},
364bdbfc029SPaul Cercueil 	[JZ4760_CLK_IPU] = {
365bdbfc029SPaul Cercueil 		"ipu", CGU_CLK_GATE,
366bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_HCLK, },
367bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 29 },
368bdbfc029SPaul Cercueil 	},
369bdbfc029SPaul Cercueil 	[JZ4760_CLK_ADC] = {
370bdbfc029SPaul Cercueil 		"adc", CGU_CLK_GATE,
371bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
372bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 14 },
373bdbfc029SPaul Cercueil 	},
374bdbfc029SPaul Cercueil 	[JZ4760_CLK_AIC] = {
375bdbfc029SPaul Cercueil 		"aic", CGU_CLK_GATE,
376bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT, },
377bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 8 },
378bdbfc029SPaul Cercueil 	},
379bdbfc029SPaul Cercueil 	[JZ4760_CLK_VPU] = {
380bdbfc029SPaul Cercueil 		"vpu", CGU_CLK_GATE,
381bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_HCLK, },
382bdbfc029SPaul Cercueil 		.gate = { CGU_REG_LCR, 30, false, 150 },
383bdbfc029SPaul Cercueil 	},
384bdbfc029SPaul Cercueil 	[JZ4760_CLK_MMC0] = {
385bdbfc029SPaul Cercueil 		"mmc0", CGU_CLK_GATE,
386bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_MMC_MUX, },
387bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 3 },
388bdbfc029SPaul Cercueil 	},
389bdbfc029SPaul Cercueil 	[JZ4760_CLK_MMC1] = {
390bdbfc029SPaul Cercueil 		"mmc1", CGU_CLK_GATE,
391bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_MMC_MUX, },
392bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 11 },
393bdbfc029SPaul Cercueil 	},
394bdbfc029SPaul Cercueil 	[JZ4760_CLK_MMC2] = {
395bdbfc029SPaul Cercueil 		"mmc2", CGU_CLK_GATE,
396bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_MMC_MUX, },
397bdbfc029SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 12 },
398bdbfc029SPaul Cercueil 	},
399bdbfc029SPaul Cercueil 	[JZ4760_CLK_UHC_PHY] = {
400bdbfc029SPaul Cercueil 		"uhc_phy", CGU_CLK_GATE,
401bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_UHC, },
402bdbfc029SPaul Cercueil 		.gate = { CGU_REG_OPCR, 5 },
403bdbfc029SPaul Cercueil 	},
404bdbfc029SPaul Cercueil 	[JZ4760_CLK_OTG_PHY] = {
405bdbfc029SPaul Cercueil 		"usb_phy", CGU_CLK_GATE,
406bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_OTG },
407bdbfc029SPaul Cercueil 		.gate = { CGU_REG_OPCR, 7, true, 50 },
408bdbfc029SPaul Cercueil 	},
409bdbfc029SPaul Cercueil 
410bdbfc029SPaul Cercueil 	/* Custom clocks */
411bdbfc029SPaul Cercueil 	[JZ4760_CLK_EXT512] = {
412bdbfc029SPaul Cercueil 		"ext/512", CGU_CLK_FIXDIV,
413bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT },
414bdbfc029SPaul Cercueil 		.fixdiv = { 512 },
415bdbfc029SPaul Cercueil 	},
416bdbfc029SPaul Cercueil 	[JZ4760_CLK_RTC] = {
417bdbfc029SPaul Cercueil 		"rtc", CGU_CLK_MUX,
418bdbfc029SPaul Cercueil 		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
419bdbfc029SPaul Cercueil 		.mux = { CGU_REG_OPCR, 2, 1},
420bdbfc029SPaul Cercueil 	},
421bdbfc029SPaul Cercueil };
422bdbfc029SPaul Cercueil 
jz4760_cgu_init(struct device_node * np)423bdbfc029SPaul Cercueil static void __init jz4760_cgu_init(struct device_node *np)
424bdbfc029SPaul Cercueil {
425bdbfc029SPaul Cercueil 	struct ingenic_cgu *cgu;
426bdbfc029SPaul Cercueil 	int retval;
427bdbfc029SPaul Cercueil 
428bdbfc029SPaul Cercueil 	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
429bdbfc029SPaul Cercueil 			      ARRAY_SIZE(jz4760_cgu_clocks), np);
430bdbfc029SPaul Cercueil 	if (!cgu) {
431bdbfc029SPaul Cercueil 		pr_err("%s: failed to initialise CGU\n", __func__);
432bdbfc029SPaul Cercueil 		return;
433bdbfc029SPaul Cercueil 	}
434bdbfc029SPaul Cercueil 
435bdbfc029SPaul Cercueil 	retval = ingenic_cgu_register_clocks(cgu);
436bdbfc029SPaul Cercueil 	if (retval)
437bdbfc029SPaul Cercueil 		pr_err("%s: failed to register CGU Clocks\n", __func__);
438bdbfc029SPaul Cercueil 
439bdbfc029SPaul Cercueil 	ingenic_cgu_register_syscore_ops(cgu);
440bdbfc029SPaul Cercueil }
441bdbfc029SPaul Cercueil 
442bdbfc029SPaul Cercueil /* We only probe via devicetree, no need for a platform driver */
443bdbfc029SPaul Cercueil CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
444bdbfc029SPaul Cercueil 
445bdbfc029SPaul Cercueil /* JZ4760B has some small differences, but we don't implement them. */
446bdbfc029SPaul Cercueil CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
447