xref: /openbmc/linux/drivers/clk/ingenic/jz4770-cgu.c (revision 7a01c19007ad3c7de15d6d8d712e01f40eeed55a)
1*7a01c190SPaul Cercueil // SPDX-License-Identifier: GPL-2.0
2*7a01c190SPaul Cercueil /*
3*7a01c190SPaul Cercueil  * JZ4770 SoC CGU driver
4*7a01c190SPaul Cercueil  * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
5*7a01c190SPaul Cercueil  */
6*7a01c190SPaul Cercueil 
7*7a01c190SPaul Cercueil #include <linux/bitops.h>
8*7a01c190SPaul Cercueil #include <linux/clk-provider.h>
9*7a01c190SPaul Cercueil #include <linux/delay.h>
10*7a01c190SPaul Cercueil #include <linux/of.h>
11*7a01c190SPaul Cercueil #include <linux/syscore_ops.h>
12*7a01c190SPaul Cercueil #include <dt-bindings/clock/jz4770-cgu.h>
13*7a01c190SPaul Cercueil #include "cgu.h"
14*7a01c190SPaul Cercueil 
15*7a01c190SPaul Cercueil /*
16*7a01c190SPaul Cercueil  * CPM registers offset address definition
17*7a01c190SPaul Cercueil  */
18*7a01c190SPaul Cercueil #define CGU_REG_CPCCR		0x00
19*7a01c190SPaul Cercueil #define CGU_REG_LCR		0x04
20*7a01c190SPaul Cercueil #define CGU_REG_CPPCR0		0x10
21*7a01c190SPaul Cercueil #define CGU_REG_CLKGR0		0x20
22*7a01c190SPaul Cercueil #define CGU_REG_OPCR		0x24
23*7a01c190SPaul Cercueil #define CGU_REG_CLKGR1		0x28
24*7a01c190SPaul Cercueil #define CGU_REG_CPPCR1		0x30
25*7a01c190SPaul Cercueil #define CGU_REG_USBPCR1		0x48
26*7a01c190SPaul Cercueil #define CGU_REG_USBCDR		0x50
27*7a01c190SPaul Cercueil #define CGU_REG_I2SCDR		0x60
28*7a01c190SPaul Cercueil #define CGU_REG_LPCDR		0x64
29*7a01c190SPaul Cercueil #define CGU_REG_MSC0CDR		0x68
30*7a01c190SPaul Cercueil #define CGU_REG_UHCCDR		0x6c
31*7a01c190SPaul Cercueil #define CGU_REG_SSICDR		0x74
32*7a01c190SPaul Cercueil #define CGU_REG_CIMCDR		0x7c
33*7a01c190SPaul Cercueil #define CGU_REG_GPSCDR		0x80
34*7a01c190SPaul Cercueil #define CGU_REG_PCMCDR		0x84
35*7a01c190SPaul Cercueil #define CGU_REG_GPUCDR		0x88
36*7a01c190SPaul Cercueil #define CGU_REG_MSC1CDR		0xA4
37*7a01c190SPaul Cercueil #define CGU_REG_MSC2CDR		0xA8
38*7a01c190SPaul Cercueil #define CGU_REG_BCHCDR		0xAC
39*7a01c190SPaul Cercueil 
40*7a01c190SPaul Cercueil /* bits within the LCR register */
41*7a01c190SPaul Cercueil #define LCR_LPM			BIT(0)		/* Low Power Mode */
42*7a01c190SPaul Cercueil 
43*7a01c190SPaul Cercueil /* bits within the OPCR register */
44*7a01c190SPaul Cercueil #define OPCR_SPENDH		BIT(5)		/* UHC PHY suspend */
45*7a01c190SPaul Cercueil #define OPCR_SPENDN		BIT(7)		/* OTG PHY suspend */
46*7a01c190SPaul Cercueil 
47*7a01c190SPaul Cercueil /* bits within the USBPCR1 register */
48*7a01c190SPaul Cercueil #define USBPCR1_UHC_POWER	BIT(5)		/* UHC PHY power down */
49*7a01c190SPaul Cercueil 
50*7a01c190SPaul Cercueil static struct ingenic_cgu *cgu;
51*7a01c190SPaul Cercueil 
52*7a01c190SPaul Cercueil static int jz4770_uhc_phy_enable(struct clk_hw *hw)
53*7a01c190SPaul Cercueil {
54*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
55*7a01c190SPaul Cercueil 	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
56*7a01c190SPaul Cercueil 
57*7a01c190SPaul Cercueil 	writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
58*7a01c190SPaul Cercueil 	writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
59*7a01c190SPaul Cercueil 	return 0;
60*7a01c190SPaul Cercueil }
61*7a01c190SPaul Cercueil 
62*7a01c190SPaul Cercueil static void jz4770_uhc_phy_disable(struct clk_hw *hw)
63*7a01c190SPaul Cercueil {
64*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
65*7a01c190SPaul Cercueil 	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
66*7a01c190SPaul Cercueil 
67*7a01c190SPaul Cercueil 	writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
68*7a01c190SPaul Cercueil 	writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
69*7a01c190SPaul Cercueil }
70*7a01c190SPaul Cercueil 
71*7a01c190SPaul Cercueil static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
72*7a01c190SPaul Cercueil {
73*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
74*7a01c190SPaul Cercueil 	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;
75*7a01c190SPaul Cercueil 
76*7a01c190SPaul Cercueil 	return !(readl(reg_opcr) & OPCR_SPENDH) &&
77*7a01c190SPaul Cercueil 		(readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
78*7a01c190SPaul Cercueil }
79*7a01c190SPaul Cercueil 
80*7a01c190SPaul Cercueil static const struct clk_ops jz4770_uhc_phy_ops = {
81*7a01c190SPaul Cercueil 	.enable = jz4770_uhc_phy_enable,
82*7a01c190SPaul Cercueil 	.disable = jz4770_uhc_phy_disable,
83*7a01c190SPaul Cercueil 	.is_enabled = jz4770_uhc_phy_is_enabled,
84*7a01c190SPaul Cercueil };
85*7a01c190SPaul Cercueil 
86*7a01c190SPaul Cercueil static int jz4770_otg_phy_enable(struct clk_hw *hw)
87*7a01c190SPaul Cercueil {
88*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
89*7a01c190SPaul Cercueil 
90*7a01c190SPaul Cercueil 	writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
91*7a01c190SPaul Cercueil 
92*7a01c190SPaul Cercueil 	/* Wait for the clock to be stable */
93*7a01c190SPaul Cercueil 	udelay(50);
94*7a01c190SPaul Cercueil 	return 0;
95*7a01c190SPaul Cercueil }
96*7a01c190SPaul Cercueil 
97*7a01c190SPaul Cercueil static void jz4770_otg_phy_disable(struct clk_hw *hw)
98*7a01c190SPaul Cercueil {
99*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
100*7a01c190SPaul Cercueil 
101*7a01c190SPaul Cercueil 	writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
102*7a01c190SPaul Cercueil }
103*7a01c190SPaul Cercueil 
104*7a01c190SPaul Cercueil static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
105*7a01c190SPaul Cercueil {
106*7a01c190SPaul Cercueil 	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;
107*7a01c190SPaul Cercueil 
108*7a01c190SPaul Cercueil 	return !!(readl(reg_opcr) & OPCR_SPENDN);
109*7a01c190SPaul Cercueil }
110*7a01c190SPaul Cercueil 
111*7a01c190SPaul Cercueil static const struct clk_ops jz4770_otg_phy_ops = {
112*7a01c190SPaul Cercueil 	.enable = jz4770_otg_phy_enable,
113*7a01c190SPaul Cercueil 	.disable = jz4770_otg_phy_disable,
114*7a01c190SPaul Cercueil 	.is_enabled = jz4770_otg_phy_is_enabled,
115*7a01c190SPaul Cercueil };
116*7a01c190SPaul Cercueil 
117*7a01c190SPaul Cercueil static const s8 pll_od_encoding[8] = {
118*7a01c190SPaul Cercueil 	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
119*7a01c190SPaul Cercueil };
120*7a01c190SPaul Cercueil 
121*7a01c190SPaul Cercueil static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
122*7a01c190SPaul Cercueil 
123*7a01c190SPaul Cercueil 	/* External clocks */
124*7a01c190SPaul Cercueil 
125*7a01c190SPaul Cercueil 	[JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
126*7a01c190SPaul Cercueil 	[JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
127*7a01c190SPaul Cercueil 
128*7a01c190SPaul Cercueil 	/* PLLs */
129*7a01c190SPaul Cercueil 
130*7a01c190SPaul Cercueil 	[JZ4770_CLK_PLL0] = {
131*7a01c190SPaul Cercueil 		"pll0", CGU_CLK_PLL,
132*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT },
133*7a01c190SPaul Cercueil 		.pll = {
134*7a01c190SPaul Cercueil 			.reg = CGU_REG_CPPCR0,
135*7a01c190SPaul Cercueil 			.m_shift = 24,
136*7a01c190SPaul Cercueil 			.m_bits = 7,
137*7a01c190SPaul Cercueil 			.m_offset = 1,
138*7a01c190SPaul Cercueil 			.n_shift = 18,
139*7a01c190SPaul Cercueil 			.n_bits = 5,
140*7a01c190SPaul Cercueil 			.n_offset = 1,
141*7a01c190SPaul Cercueil 			.od_shift = 16,
142*7a01c190SPaul Cercueil 			.od_bits = 2,
143*7a01c190SPaul Cercueil 			.od_max = 8,
144*7a01c190SPaul Cercueil 			.od_encoding = pll_od_encoding,
145*7a01c190SPaul Cercueil 			.bypass_bit = 9,
146*7a01c190SPaul Cercueil 			.enable_bit = 8,
147*7a01c190SPaul Cercueil 			.stable_bit = 10,
148*7a01c190SPaul Cercueil 		},
149*7a01c190SPaul Cercueil 	},
150*7a01c190SPaul Cercueil 
151*7a01c190SPaul Cercueil 	[JZ4770_CLK_PLL1] = {
152*7a01c190SPaul Cercueil 		/* TODO: PLL1 can depend on PLL0 */
153*7a01c190SPaul Cercueil 		"pll1", CGU_CLK_PLL,
154*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT },
155*7a01c190SPaul Cercueil 		.pll = {
156*7a01c190SPaul Cercueil 			.reg = CGU_REG_CPPCR1,
157*7a01c190SPaul Cercueil 			.m_shift = 24,
158*7a01c190SPaul Cercueil 			.m_bits = 7,
159*7a01c190SPaul Cercueil 			.m_offset = 1,
160*7a01c190SPaul Cercueil 			.n_shift = 18,
161*7a01c190SPaul Cercueil 			.n_bits = 5,
162*7a01c190SPaul Cercueil 			.n_offset = 1,
163*7a01c190SPaul Cercueil 			.od_shift = 16,
164*7a01c190SPaul Cercueil 			.od_bits = 2,
165*7a01c190SPaul Cercueil 			.od_max = 8,
166*7a01c190SPaul Cercueil 			.od_encoding = pll_od_encoding,
167*7a01c190SPaul Cercueil 			.enable_bit = 7,
168*7a01c190SPaul Cercueil 			.stable_bit = 6,
169*7a01c190SPaul Cercueil 			.no_bypass_bit = true,
170*7a01c190SPaul Cercueil 		},
171*7a01c190SPaul Cercueil 	},
172*7a01c190SPaul Cercueil 
173*7a01c190SPaul Cercueil 	/* Main clocks */
174*7a01c190SPaul Cercueil 
175*7a01c190SPaul Cercueil 	[JZ4770_CLK_CCLK] = {
176*7a01c190SPaul Cercueil 		"cclk", CGU_CLK_DIV,
177*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
178*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
179*7a01c190SPaul Cercueil 	},
180*7a01c190SPaul Cercueil 	[JZ4770_CLK_H0CLK] = {
181*7a01c190SPaul Cercueil 		"h0clk", CGU_CLK_DIV,
182*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
183*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
184*7a01c190SPaul Cercueil 	},
185*7a01c190SPaul Cercueil 	[JZ4770_CLK_H1CLK] = {
186*7a01c190SPaul Cercueil 		"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
187*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
188*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
189*7a01c190SPaul Cercueil 		.gate = { CGU_REG_LCR, 30 },
190*7a01c190SPaul Cercueil 	},
191*7a01c190SPaul Cercueil 	[JZ4770_CLK_H2CLK] = {
192*7a01c190SPaul Cercueil 		"h2clk", CGU_CLK_DIV,
193*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
194*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
195*7a01c190SPaul Cercueil 	},
196*7a01c190SPaul Cercueil 	[JZ4770_CLK_C1CLK] = {
197*7a01c190SPaul Cercueil 		"c1clk", CGU_CLK_DIV,
198*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
199*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
200*7a01c190SPaul Cercueil 	},
201*7a01c190SPaul Cercueil 	[JZ4770_CLK_PCLK] = {
202*7a01c190SPaul Cercueil 		"pclk", CGU_CLK_DIV,
203*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, },
204*7a01c190SPaul Cercueil 		.div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
205*7a01c190SPaul Cercueil 	},
206*7a01c190SPaul Cercueil 
207*7a01c190SPaul Cercueil 	/* Those divided clocks can connect to PLL0 or PLL1 */
208*7a01c190SPaul Cercueil 
209*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC0_MUX] = {
210*7a01c190SPaul Cercueil 		"mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
211*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
212*7a01c190SPaul Cercueil 		.mux = { CGU_REG_MSC0CDR, 30, 1 },
213*7a01c190SPaul Cercueil 		.div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
214*7a01c190SPaul Cercueil 		.gate = { CGU_REG_MSC0CDR, 31 },
215*7a01c190SPaul Cercueil 	},
216*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC1_MUX] = {
217*7a01c190SPaul Cercueil 		"mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
218*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
219*7a01c190SPaul Cercueil 		.mux = { CGU_REG_MSC1CDR, 30, 1 },
220*7a01c190SPaul Cercueil 		.div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
221*7a01c190SPaul Cercueil 		.gate = { CGU_REG_MSC1CDR, 31 },
222*7a01c190SPaul Cercueil 	},
223*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC2_MUX] = {
224*7a01c190SPaul Cercueil 		"mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
225*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
226*7a01c190SPaul Cercueil 		.mux = { CGU_REG_MSC2CDR, 30, 1 },
227*7a01c190SPaul Cercueil 		.div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
228*7a01c190SPaul Cercueil 		.gate = { CGU_REG_MSC2CDR, 31 },
229*7a01c190SPaul Cercueil 	},
230*7a01c190SPaul Cercueil 	[JZ4770_CLK_CIM] = {
231*7a01c190SPaul Cercueil 		"cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
232*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
233*7a01c190SPaul Cercueil 		.mux = { CGU_REG_CIMCDR, 31, 1 },
234*7a01c190SPaul Cercueil 		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
235*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 26 },
236*7a01c190SPaul Cercueil 	},
237*7a01c190SPaul Cercueil 	[JZ4770_CLK_UHC] = {
238*7a01c190SPaul Cercueil 		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
239*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
240*7a01c190SPaul Cercueil 		.mux = { CGU_REG_UHCCDR, 29, 1 },
241*7a01c190SPaul Cercueil 		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
242*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 24 },
243*7a01c190SPaul Cercueil 	},
244*7a01c190SPaul Cercueil 	[JZ4770_CLK_GPU] = {
245*7a01c190SPaul Cercueil 		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
246*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
247*7a01c190SPaul Cercueil 		.mux = { CGU_REG_GPUCDR, 31, 1 },
248*7a01c190SPaul Cercueil 		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
249*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 9 },
250*7a01c190SPaul Cercueil 	},
251*7a01c190SPaul Cercueil 	[JZ4770_CLK_BCH] = {
252*7a01c190SPaul Cercueil 		"bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
253*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
254*7a01c190SPaul Cercueil 		.mux = { CGU_REG_BCHCDR, 31, 1 },
255*7a01c190SPaul Cercueil 		.div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
256*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 1 },
257*7a01c190SPaul Cercueil 	},
258*7a01c190SPaul Cercueil 	[JZ4770_CLK_LPCLK_MUX] = {
259*7a01c190SPaul Cercueil 		"lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
260*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
261*7a01c190SPaul Cercueil 		.mux = { CGU_REG_LPCDR, 29, 1 },
262*7a01c190SPaul Cercueil 		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
263*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 28 },
264*7a01c190SPaul Cercueil 	},
265*7a01c190SPaul Cercueil 	[JZ4770_CLK_GPS] = {
266*7a01c190SPaul Cercueil 		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
267*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
268*7a01c190SPaul Cercueil 		.mux = { CGU_REG_GPSCDR, 31, 1 },
269*7a01c190SPaul Cercueil 		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
270*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 22 },
271*7a01c190SPaul Cercueil 	},
272*7a01c190SPaul Cercueil 
273*7a01c190SPaul Cercueil 	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
274*7a01c190SPaul Cercueil 
275*7a01c190SPaul Cercueil 	[JZ4770_CLK_SSI_MUX] = {
276*7a01c190SPaul Cercueil 		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
277*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, -1,
278*7a01c190SPaul Cercueil 			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
279*7a01c190SPaul Cercueil 		.mux = { CGU_REG_SSICDR, 30, 2 },
280*7a01c190SPaul Cercueil 		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
281*7a01c190SPaul Cercueil 	},
282*7a01c190SPaul Cercueil 	[JZ4770_CLK_PCM_MUX] = {
283*7a01c190SPaul Cercueil 		"pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
284*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, -1,
285*7a01c190SPaul Cercueil 			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
286*7a01c190SPaul Cercueil 		.mux = { CGU_REG_PCMCDR, 30, 2 },
287*7a01c190SPaul Cercueil 		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
288*7a01c190SPaul Cercueil 	},
289*7a01c190SPaul Cercueil 	[JZ4770_CLK_I2S] = {
290*7a01c190SPaul Cercueil 		"i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
291*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, -1,
292*7a01c190SPaul Cercueil 			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
293*7a01c190SPaul Cercueil 		.mux = { CGU_REG_I2SCDR, 30, 2 },
294*7a01c190SPaul Cercueil 		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
295*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 13 },
296*7a01c190SPaul Cercueil 	},
297*7a01c190SPaul Cercueil 	[JZ4770_CLK_OTG] = {
298*7a01c190SPaul Cercueil 		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
299*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, -1,
300*7a01c190SPaul Cercueil 			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
301*7a01c190SPaul Cercueil 		.mux = { CGU_REG_USBCDR, 30, 2 },
302*7a01c190SPaul Cercueil 		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
303*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 2 },
304*7a01c190SPaul Cercueil 	},
305*7a01c190SPaul Cercueil 
306*7a01c190SPaul Cercueil 	/* Gate-only clocks */
307*7a01c190SPaul Cercueil 
308*7a01c190SPaul Cercueil 	[JZ4770_CLK_SSI0] = {
309*7a01c190SPaul Cercueil 		"ssi0", CGU_CLK_GATE,
310*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_SSI_MUX, },
311*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 4 },
312*7a01c190SPaul Cercueil 	},
313*7a01c190SPaul Cercueil 	[JZ4770_CLK_SSI1] = {
314*7a01c190SPaul Cercueil 		"ssi1", CGU_CLK_GATE,
315*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_SSI_MUX, },
316*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 19 },
317*7a01c190SPaul Cercueil 	},
318*7a01c190SPaul Cercueil 	[JZ4770_CLK_SSI2] = {
319*7a01c190SPaul Cercueil 		"ssi2", CGU_CLK_GATE,
320*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_SSI_MUX, },
321*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 20 },
322*7a01c190SPaul Cercueil 	},
323*7a01c190SPaul Cercueil 	[JZ4770_CLK_PCM0] = {
324*7a01c190SPaul Cercueil 		"pcm0", CGU_CLK_GATE,
325*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PCM_MUX, },
326*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 8 },
327*7a01c190SPaul Cercueil 	},
328*7a01c190SPaul Cercueil 	[JZ4770_CLK_PCM1] = {
329*7a01c190SPaul Cercueil 		"pcm1", CGU_CLK_GATE,
330*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_PCM_MUX, },
331*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 10 },
332*7a01c190SPaul Cercueil 	},
333*7a01c190SPaul Cercueil 	[JZ4770_CLK_DMA] = {
334*7a01c190SPaul Cercueil 		"dma", CGU_CLK_GATE,
335*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_H2CLK, },
336*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 21 },
337*7a01c190SPaul Cercueil 	},
338*7a01c190SPaul Cercueil 	[JZ4770_CLK_I2C0] = {
339*7a01c190SPaul Cercueil 		"i2c0", CGU_CLK_GATE,
340*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
341*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 5 },
342*7a01c190SPaul Cercueil 	},
343*7a01c190SPaul Cercueil 	[JZ4770_CLK_I2C1] = {
344*7a01c190SPaul Cercueil 		"i2c1", CGU_CLK_GATE,
345*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
346*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 6 },
347*7a01c190SPaul Cercueil 	},
348*7a01c190SPaul Cercueil 	[JZ4770_CLK_I2C2] = {
349*7a01c190SPaul Cercueil 		"i2c2", CGU_CLK_GATE,
350*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
351*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 15 },
352*7a01c190SPaul Cercueil 	},
353*7a01c190SPaul Cercueil 	[JZ4770_CLK_UART0] = {
354*7a01c190SPaul Cercueil 		"uart0", CGU_CLK_GATE,
355*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
356*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 15 },
357*7a01c190SPaul Cercueil 	},
358*7a01c190SPaul Cercueil 	[JZ4770_CLK_UART1] = {
359*7a01c190SPaul Cercueil 		"uart1", CGU_CLK_GATE,
360*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
361*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 16 },
362*7a01c190SPaul Cercueil 	},
363*7a01c190SPaul Cercueil 	[JZ4770_CLK_UART2] = {
364*7a01c190SPaul Cercueil 		"uart2", CGU_CLK_GATE,
365*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
366*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 17 },
367*7a01c190SPaul Cercueil 	},
368*7a01c190SPaul Cercueil 	[JZ4770_CLK_UART3] = {
369*7a01c190SPaul Cercueil 		"uart3", CGU_CLK_GATE,
370*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
371*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 18 },
372*7a01c190SPaul Cercueil 	},
373*7a01c190SPaul Cercueil 	[JZ4770_CLK_IPU] = {
374*7a01c190SPaul Cercueil 		"ipu", CGU_CLK_GATE,
375*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_H0CLK, },
376*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 29 },
377*7a01c190SPaul Cercueil 	},
378*7a01c190SPaul Cercueil 	[JZ4770_CLK_ADC] = {
379*7a01c190SPaul Cercueil 		"adc", CGU_CLK_GATE,
380*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
381*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 14 },
382*7a01c190SPaul Cercueil 	},
383*7a01c190SPaul Cercueil 	[JZ4770_CLK_AIC] = {
384*7a01c190SPaul Cercueil 		"aic", CGU_CLK_GATE,
385*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT, },
386*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 8 },
387*7a01c190SPaul Cercueil 	},
388*7a01c190SPaul Cercueil 	[JZ4770_CLK_AUX] = {
389*7a01c190SPaul Cercueil 		"aux", CGU_CLK_GATE,
390*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_C1CLK, },
391*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 14 },
392*7a01c190SPaul Cercueil 	},
393*7a01c190SPaul Cercueil 	[JZ4770_CLK_VPU] = {
394*7a01c190SPaul Cercueil 		"vpu", CGU_CLK_GATE,
395*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_H1CLK, },
396*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR1, 7 },
397*7a01c190SPaul Cercueil 	},
398*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC0] = {
399*7a01c190SPaul Cercueil 		"mmc0", CGU_CLK_GATE,
400*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_MMC0_MUX, },
401*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 3 },
402*7a01c190SPaul Cercueil 	},
403*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC1] = {
404*7a01c190SPaul Cercueil 		"mmc1", CGU_CLK_GATE,
405*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_MMC1_MUX, },
406*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 11 },
407*7a01c190SPaul Cercueil 	},
408*7a01c190SPaul Cercueil 	[JZ4770_CLK_MMC2] = {
409*7a01c190SPaul Cercueil 		"mmc2", CGU_CLK_GATE,
410*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_MMC2_MUX, },
411*7a01c190SPaul Cercueil 		.gate = { CGU_REG_CLKGR0, 12 },
412*7a01c190SPaul Cercueil 	},
413*7a01c190SPaul Cercueil 
414*7a01c190SPaul Cercueil 	/* Custom clocks */
415*7a01c190SPaul Cercueil 
416*7a01c190SPaul Cercueil 	[JZ4770_CLK_UHC_PHY] = {
417*7a01c190SPaul Cercueil 		"uhc_phy", CGU_CLK_CUSTOM,
418*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_UHC, -1, -1, -1 },
419*7a01c190SPaul Cercueil 		.custom = { &jz4770_uhc_phy_ops },
420*7a01c190SPaul Cercueil 	},
421*7a01c190SPaul Cercueil 	[JZ4770_CLK_OTG_PHY] = {
422*7a01c190SPaul Cercueil 		"usb_phy", CGU_CLK_CUSTOM,
423*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_OTG, -1, -1, -1 },
424*7a01c190SPaul Cercueil 		.custom = { &jz4770_otg_phy_ops },
425*7a01c190SPaul Cercueil 	},
426*7a01c190SPaul Cercueil 
427*7a01c190SPaul Cercueil 	[JZ4770_CLK_EXT512] = {
428*7a01c190SPaul Cercueil 		"ext/512", CGU_CLK_FIXDIV,
429*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT },
430*7a01c190SPaul Cercueil 		.fixdiv = { 512 },
431*7a01c190SPaul Cercueil 	},
432*7a01c190SPaul Cercueil 
433*7a01c190SPaul Cercueil 	[JZ4770_CLK_RTC] = {
434*7a01c190SPaul Cercueil 		"rtc", CGU_CLK_MUX,
435*7a01c190SPaul Cercueil 		.parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
436*7a01c190SPaul Cercueil 		.mux = { CGU_REG_OPCR, 2, 1},
437*7a01c190SPaul Cercueil 	},
438*7a01c190SPaul Cercueil };
439*7a01c190SPaul Cercueil 
440*7a01c190SPaul Cercueil #if IS_ENABLED(CONFIG_PM_SLEEP)
441*7a01c190SPaul Cercueil static int jz4770_cgu_pm_suspend(void)
442*7a01c190SPaul Cercueil {
443*7a01c190SPaul Cercueil 	u32 val;
444*7a01c190SPaul Cercueil 
445*7a01c190SPaul Cercueil 	val = readl(cgu->base + CGU_REG_LCR);
446*7a01c190SPaul Cercueil 	writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
447*7a01c190SPaul Cercueil 	return 0;
448*7a01c190SPaul Cercueil }
449*7a01c190SPaul Cercueil 
450*7a01c190SPaul Cercueil static void jz4770_cgu_pm_resume(void)
451*7a01c190SPaul Cercueil {
452*7a01c190SPaul Cercueil 	u32 val;
453*7a01c190SPaul Cercueil 
454*7a01c190SPaul Cercueil 	val = readl(cgu->base + CGU_REG_LCR);
455*7a01c190SPaul Cercueil 	writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
456*7a01c190SPaul Cercueil }
457*7a01c190SPaul Cercueil 
458*7a01c190SPaul Cercueil static struct syscore_ops jz4770_cgu_pm_ops = {
459*7a01c190SPaul Cercueil 	.suspend = jz4770_cgu_pm_suspend,
460*7a01c190SPaul Cercueil 	.resume = jz4770_cgu_pm_resume,
461*7a01c190SPaul Cercueil };
462*7a01c190SPaul Cercueil #endif /* CONFIG_PM_SLEEP */
463*7a01c190SPaul Cercueil 
464*7a01c190SPaul Cercueil static void __init jz4770_cgu_init(struct device_node *np)
465*7a01c190SPaul Cercueil {
466*7a01c190SPaul Cercueil 	int retval;
467*7a01c190SPaul Cercueil 
468*7a01c190SPaul Cercueil 	cgu = ingenic_cgu_new(jz4770_cgu_clocks,
469*7a01c190SPaul Cercueil 			      ARRAY_SIZE(jz4770_cgu_clocks), np);
470*7a01c190SPaul Cercueil 	if (!cgu)
471*7a01c190SPaul Cercueil 		pr_err("%s: failed to initialise CGU\n", __func__);
472*7a01c190SPaul Cercueil 
473*7a01c190SPaul Cercueil 	retval = ingenic_cgu_register_clocks(cgu);
474*7a01c190SPaul Cercueil 	if (retval)
475*7a01c190SPaul Cercueil 		pr_err("%s: failed to register CGU Clocks\n", __func__);
476*7a01c190SPaul Cercueil 
477*7a01c190SPaul Cercueil #if IS_ENABLED(CONFIG_PM_SLEEP)
478*7a01c190SPaul Cercueil 	register_syscore_ops(&jz4770_cgu_pm_ops);
479*7a01c190SPaul Cercueil #endif
480*7a01c190SPaul Cercueil }
481*7a01c190SPaul Cercueil 
482*7a01c190SPaul Cercueil /* We only probe via devicetree, no need for a platform driver */
483*7a01c190SPaul Cercueil CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
484