xref: /openbmc/linux/drivers/clk/ingenic/jz4740-cgu.c (revision ff1930c6bdf031e72e101a8aa47d54e73a745f93)
1*ff1930c6SPaul Burton /*
2*ff1930c6SPaul Burton  * Ingenic JZ4740 SoC CGU driver
3*ff1930c6SPaul Burton  *
4*ff1930c6SPaul Burton  * Copyright (c) 2015 Imagination Technologies
5*ff1930c6SPaul Burton  * Author: Paul Burton <paul.burton@imgtec.com>
6*ff1930c6SPaul Burton  *
7*ff1930c6SPaul Burton  * This program is free software; you can redistribute it and/or
8*ff1930c6SPaul Burton  * modify it under the terms of the GNU General Public License as
9*ff1930c6SPaul Burton  * published by the Free Software Foundation; either version 2 of
10*ff1930c6SPaul Burton  * the License, or (at your option) any later version.
11*ff1930c6SPaul Burton  *
12*ff1930c6SPaul Burton  * This program is distributed in the hope that it will be useful,
13*ff1930c6SPaul Burton  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*ff1930c6SPaul Burton  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*ff1930c6SPaul Burton  * GNU General Public License for more details.
16*ff1930c6SPaul Burton  */
17*ff1930c6SPaul Burton 
18*ff1930c6SPaul Burton #include <linux/clk-provider.h>
19*ff1930c6SPaul Burton #include <linux/delay.h>
20*ff1930c6SPaul Burton #include <linux/of.h>
21*ff1930c6SPaul Burton #include <dt-bindings/clock/jz4740-cgu.h>
22*ff1930c6SPaul Burton #include "cgu.h"
23*ff1930c6SPaul Burton 
24*ff1930c6SPaul Burton /* CGU register offsets */
25*ff1930c6SPaul Burton #define CGU_REG_CPCCR		0x00
26*ff1930c6SPaul Burton #define CGU_REG_CPPCR		0x10
27*ff1930c6SPaul Burton #define CGU_REG_SCR		0x24
28*ff1930c6SPaul Burton #define CGU_REG_I2SCDR		0x60
29*ff1930c6SPaul Burton #define CGU_REG_LPCDR		0x64
30*ff1930c6SPaul Burton #define CGU_REG_MSCCDR		0x68
31*ff1930c6SPaul Burton #define CGU_REG_UHCCDR		0x6c
32*ff1930c6SPaul Burton #define CGU_REG_SSICDR		0x74
33*ff1930c6SPaul Burton 
34*ff1930c6SPaul Burton /* bits within a PLL control register */
35*ff1930c6SPaul Burton #define PLLCTL_M_SHIFT		23
36*ff1930c6SPaul Burton #define PLLCTL_M_MASK		(0x1ff << PLLCTL_M_SHIFT)
37*ff1930c6SPaul Burton #define PLLCTL_N_SHIFT		18
38*ff1930c6SPaul Burton #define PLLCTL_N_MASK		(0x1f << PLLCTL_N_SHIFT)
39*ff1930c6SPaul Burton #define PLLCTL_OD_SHIFT		16
40*ff1930c6SPaul Burton #define PLLCTL_OD_MASK		(0x3 << PLLCTL_OD_SHIFT)
41*ff1930c6SPaul Burton #define PLLCTL_STABLE		(1 << 10)
42*ff1930c6SPaul Burton #define PLLCTL_BYPASS		(1 << 9)
43*ff1930c6SPaul Burton #define PLLCTL_ENABLE		(1 << 8)
44*ff1930c6SPaul Burton 
45*ff1930c6SPaul Burton static struct ingenic_cgu *cgu;
46*ff1930c6SPaul Burton 
47*ff1930c6SPaul Burton static const s8 pll_od_encoding[4] = {
48*ff1930c6SPaul Burton 	0x0, 0x1, -1, 0x3,
49*ff1930c6SPaul Burton };
50*ff1930c6SPaul Burton 
51*ff1930c6SPaul Burton static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
52*ff1930c6SPaul Burton 
53*ff1930c6SPaul Burton 	/* External clocks */
54*ff1930c6SPaul Burton 
55*ff1930c6SPaul Burton 	[JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
56*ff1930c6SPaul Burton 	[JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
57*ff1930c6SPaul Burton 
58*ff1930c6SPaul Burton 	[JZ4740_CLK_PLL] = {
59*ff1930c6SPaul Burton 		"pll", CGU_CLK_PLL,
60*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
61*ff1930c6SPaul Burton 		.pll = {
62*ff1930c6SPaul Burton 			.reg = CGU_REG_CPPCR,
63*ff1930c6SPaul Burton 			.m_shift = 23,
64*ff1930c6SPaul Burton 			.m_bits = 9,
65*ff1930c6SPaul Burton 			.m_offset = 2,
66*ff1930c6SPaul Burton 			.n_shift = 18,
67*ff1930c6SPaul Burton 			.n_bits = 5,
68*ff1930c6SPaul Burton 			.n_offset = 2,
69*ff1930c6SPaul Burton 			.od_shift = 16,
70*ff1930c6SPaul Burton 			.od_bits = 2,
71*ff1930c6SPaul Burton 			.od_max = 4,
72*ff1930c6SPaul Burton 			.od_encoding = pll_od_encoding,
73*ff1930c6SPaul Burton 			.stable_bit = 10,
74*ff1930c6SPaul Burton 			.bypass_bit = 9,
75*ff1930c6SPaul Burton 			.enable_bit = 8,
76*ff1930c6SPaul Burton 		},
77*ff1930c6SPaul Burton 	},
78*ff1930c6SPaul Burton 
79*ff1930c6SPaul Burton 	/* Muxes & dividers */
80*ff1930c6SPaul Burton 
81*ff1930c6SPaul Burton 	[JZ4740_CLK_PLL_HALF] = {
82*ff1930c6SPaul Burton 		"pll half", CGU_CLK_DIV,
83*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
84*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
85*ff1930c6SPaul Burton 	},
86*ff1930c6SPaul Burton 
87*ff1930c6SPaul Burton 	[JZ4740_CLK_CCLK] = {
88*ff1930c6SPaul Burton 		"cclk", CGU_CLK_DIV,
89*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
90*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
91*ff1930c6SPaul Burton 	},
92*ff1930c6SPaul Burton 
93*ff1930c6SPaul Burton 	[JZ4740_CLK_HCLK] = {
94*ff1930c6SPaul Burton 		"hclk", CGU_CLK_DIV,
95*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
96*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
97*ff1930c6SPaul Burton 	},
98*ff1930c6SPaul Burton 
99*ff1930c6SPaul Burton 	[JZ4740_CLK_PCLK] = {
100*ff1930c6SPaul Burton 		"pclk", CGU_CLK_DIV,
101*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
102*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
103*ff1930c6SPaul Burton 	},
104*ff1930c6SPaul Burton 
105*ff1930c6SPaul Burton 	[JZ4740_CLK_MCLK] = {
106*ff1930c6SPaul Burton 		"mclk", CGU_CLK_DIV,
107*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
108*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
109*ff1930c6SPaul Burton 	},
110*ff1930c6SPaul Burton 
111*ff1930c6SPaul Burton 	[JZ4740_CLK_LCD] = {
112*ff1930c6SPaul Burton 		"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
113*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
114*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
115*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 10 },
116*ff1930c6SPaul Burton 	},
117*ff1930c6SPaul Burton 
118*ff1930c6SPaul Burton 	[JZ4740_CLK_LCD_PCLK] = {
119*ff1930c6SPaul Burton 		"lcd_pclk", CGU_CLK_DIV,
120*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
121*ff1930c6SPaul Burton 		.div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
122*ff1930c6SPaul Burton 	},
123*ff1930c6SPaul Burton 
124*ff1930c6SPaul Burton 	[JZ4740_CLK_I2S] = {
125*ff1930c6SPaul Burton 		"i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
126*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
127*ff1930c6SPaul Burton 		.mux = { CGU_REG_CPCCR, 31, 1 },
128*ff1930c6SPaul Burton 		.div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
129*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 6 },
130*ff1930c6SPaul Burton 	},
131*ff1930c6SPaul Burton 
132*ff1930c6SPaul Burton 	[JZ4740_CLK_SPI] = {
133*ff1930c6SPaul Burton 		"spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
134*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
135*ff1930c6SPaul Burton 		.mux = { CGU_REG_SSICDR, 31, 1 },
136*ff1930c6SPaul Burton 		.div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
137*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 4 },
138*ff1930c6SPaul Burton 	},
139*ff1930c6SPaul Burton 
140*ff1930c6SPaul Burton 	[JZ4740_CLK_MMC] = {
141*ff1930c6SPaul Burton 		"mmc", CGU_CLK_DIV | CGU_CLK_GATE,
142*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
143*ff1930c6SPaul Burton 		.div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
144*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 7 },
145*ff1930c6SPaul Burton 	},
146*ff1930c6SPaul Burton 
147*ff1930c6SPaul Burton 	[JZ4740_CLK_UHC] = {
148*ff1930c6SPaul Burton 		"uhc", CGU_CLK_DIV | CGU_CLK_GATE,
149*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
150*ff1930c6SPaul Burton 		.div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
151*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 14 },
152*ff1930c6SPaul Burton 	},
153*ff1930c6SPaul Burton 
154*ff1930c6SPaul Burton 	[JZ4740_CLK_UDC] = {
155*ff1930c6SPaul Burton 		"udc", CGU_CLK_MUX | CGU_CLK_DIV,
156*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
157*ff1930c6SPaul Burton 		.mux = { CGU_REG_CPCCR, 29, 1 },
158*ff1930c6SPaul Burton 		.div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
159*ff1930c6SPaul Burton 		.gate = { CGU_REG_SCR, 6 },
160*ff1930c6SPaul Burton 	},
161*ff1930c6SPaul Burton 
162*ff1930c6SPaul Burton 	/* Gate-only clocks */
163*ff1930c6SPaul Burton 
164*ff1930c6SPaul Burton 	[JZ4740_CLK_UART0] = {
165*ff1930c6SPaul Burton 		"uart0", CGU_CLK_GATE,
166*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
167*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 0 },
168*ff1930c6SPaul Burton 	},
169*ff1930c6SPaul Burton 
170*ff1930c6SPaul Burton 	[JZ4740_CLK_UART1] = {
171*ff1930c6SPaul Burton 		"uart1", CGU_CLK_GATE,
172*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
173*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 15 },
174*ff1930c6SPaul Burton 	},
175*ff1930c6SPaul Burton 
176*ff1930c6SPaul Burton 	[JZ4740_CLK_DMA] = {
177*ff1930c6SPaul Burton 		"dma", CGU_CLK_GATE,
178*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
179*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 12 },
180*ff1930c6SPaul Burton 	},
181*ff1930c6SPaul Burton 
182*ff1930c6SPaul Burton 	[JZ4740_CLK_IPU] = {
183*ff1930c6SPaul Burton 		"ipu", CGU_CLK_GATE,
184*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
185*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 13 },
186*ff1930c6SPaul Burton 	},
187*ff1930c6SPaul Burton 
188*ff1930c6SPaul Burton 	[JZ4740_CLK_ADC] = {
189*ff1930c6SPaul Burton 		"adc", CGU_CLK_GATE,
190*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
191*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 8 },
192*ff1930c6SPaul Burton 	},
193*ff1930c6SPaul Burton 
194*ff1930c6SPaul Burton 	[JZ4740_CLK_I2C] = {
195*ff1930c6SPaul Burton 		"i2c", CGU_CLK_GATE,
196*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
197*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 3 },
198*ff1930c6SPaul Burton 	},
199*ff1930c6SPaul Burton 
200*ff1930c6SPaul Burton 	[JZ4740_CLK_AIC] = {
201*ff1930c6SPaul Burton 		"aic", CGU_CLK_GATE,
202*ff1930c6SPaul Burton 		.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
203*ff1930c6SPaul Burton 		.gate = { CGU_REG_CLKGR, 5 },
204*ff1930c6SPaul Burton 	},
205*ff1930c6SPaul Burton };
206*ff1930c6SPaul Burton 
207*ff1930c6SPaul Burton static void __init jz4740_cgu_init(struct device_node *np)
208*ff1930c6SPaul Burton {
209*ff1930c6SPaul Burton 	int retval;
210*ff1930c6SPaul Burton 
211*ff1930c6SPaul Burton 	cgu = ingenic_cgu_new(jz4740_cgu_clocks,
212*ff1930c6SPaul Burton 			      ARRAY_SIZE(jz4740_cgu_clocks), np);
213*ff1930c6SPaul Burton 	if (!cgu) {
214*ff1930c6SPaul Burton 		pr_err("%s: failed to initialise CGU\n", __func__);
215*ff1930c6SPaul Burton 		return;
216*ff1930c6SPaul Burton 	}
217*ff1930c6SPaul Burton 
218*ff1930c6SPaul Burton 	retval = ingenic_cgu_register_clocks(cgu);
219*ff1930c6SPaul Burton 	if (retval)
220*ff1930c6SPaul Burton 		pr_err("%s: failed to register CGU Clocks\n", __func__);
221*ff1930c6SPaul Burton }
222*ff1930c6SPaul Burton CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
223