aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/clock-sh7372.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2010-05-12 10:21:34 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-05-19 23:07:29 -0400
commit495b3cea94135a97e919bca67d7dcfdefafc7767 (patch)
tree480e9fbe9e8d946cd837da0eec244733986939a6 /arch/arm/mach-shmobile/clock-sh7372.c
parente47bb515c57853c1f41474dae199cb033e747f66 (diff)
ARM: mach-shmobile: sh7372 clock framework support V2
This patch is V2 of clock framework tables/code for sh7372. MSTP are included for KEYSC, SCIF, IIC, USB, SDHI and UIO. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile/clock-sh7372.c')
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
new file mode 100644
index 000000000000..ac46b4bce522
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -0,0 +1,387 @@
1/*
2 * SH7372 clock framework support
3 *
4 * Copyright (C) 2010 Magnus Damm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/platform_device.h>
22#include <linux/io.h>
23#include <linux/sh_clk.h>
24#include <mach/common.h>
25#include <asm/clkdev.h>
26
27/* SH7372 registers */
28#define FRQCRA 0xe6150000
29#define FRQCRB 0xe6150004
30#define FRQCRC 0xe61500e0
31#define FRQCRD 0xe61500e4
32#define VCLKCR1 0xe6150008
33#define VCLKCR2 0xe615000c
34#define VCLKCR3 0xe615001c
35#define FMSICKCR 0xe6150010
36#define FMSOCKCR 0xe6150014
37#define FSIACKCR 0xe6150018
38#define FSIBCKCR 0xe6150090
39#define SUBCKCR 0xe6150080
40#define SPUCKCR 0xe6150084
41#define VOUCKCR 0xe6150088
42#define HDMICKCR 0xe6150094
43#define DSITCKCR 0xe6150060
44#define DSI0PCKCR 0xe6150064
45#define DSI1PCKCR 0xe6150098
46#define PLLC01CR 0xe6150028
47#define PLLC2CR 0xe615002c
48#define SMSTPCR0 0xe6150130
49#define SMSTPCR1 0xe6150134
50#define SMSTPCR2 0xe6150138
51#define SMSTPCR3 0xe615013c
52#define SMSTPCR4 0xe6150140
53
54/* Fixed 32 KHz root clock from EXTALR pin */
55static struct clk r_clk = {
56 .rate = 32768,
57};
58
59/*
60 * 26MHz default rate for the EXTAL1 root input clock.
61 * If needed, reset this with clk_set_rate() from the platform code.
62 */
63struct clk extal1_clk = {
64 .rate = 26666666,
65};
66
67/*
68 * 48MHz default rate for the EXTAL2 root input clock.
69 * If needed, reset this with clk_set_rate() from the platform code.
70 */
71struct clk extal2_clk = {
72 .rate = 48000000,
73};
74
75/* A fixed divide-by-2 block */
76static unsigned long div2_recalc(struct clk *clk)
77{
78 return clk->parent->rate / 2;
79}
80
81static struct clk_ops div2_clk_ops = {
82 .recalc = div2_recalc,
83};
84
85/* Divide extal1 by two */
86static struct clk extal1_div2_clk = {
87 .ops = &div2_clk_ops,
88 .parent = &extal1_clk,
89};
90
91/* Divide extal2 by two */
92static struct clk extal2_div2_clk = {
93 .ops = &div2_clk_ops,
94 .parent = &extal2_clk,
95};
96
97/* Divide extal2 by four */
98static struct clk extal2_div4_clk = {
99 .ops = &div2_clk_ops,
100 .parent = &extal2_div2_clk,
101};
102
103/* PLLC0 and PLLC1 */
104static unsigned long pllc01_recalc(struct clk *clk)
105{
106 unsigned long mult = 1;
107
108 if (__raw_readl(PLLC01CR) & (1 << 14))
109 mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1) * 2;
110
111 return clk->parent->rate * mult;
112}
113
114static struct clk_ops pllc01_clk_ops = {
115 .recalc = pllc01_recalc,
116};
117
118static struct clk pllc0_clk = {
119 .ops = &pllc01_clk_ops,
120 .flags = CLK_ENABLE_ON_INIT,
121 .parent = &extal1_div2_clk,
122 .enable_reg = (void __iomem *)FRQCRC,
123};
124
125static struct clk pllc1_clk = {
126 .ops = &pllc01_clk_ops,
127 .flags = CLK_ENABLE_ON_INIT,
128 .parent = &extal1_div2_clk,
129 .enable_reg = (void __iomem *)FRQCRA,
130};
131
132/* Divide PLLC1 by two */
133static struct clk pllc1_div2_clk = {
134 .ops = &div2_clk_ops,
135 .parent = &pllc1_clk,
136};
137
138/* PLLC2 */
139static unsigned long pllc2_recalc(struct clk *clk)
140{
141 unsigned long mult = 1;
142
143 if (__raw_readl(PLLC2CR) & (1 << 31))
144 mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
145
146 return clk->parent->rate * mult;
147}
148
149static struct clk_ops pllc2_clk_ops = {
150 .recalc = pllc2_recalc,
151};
152
153static struct clk pllc2_clk = {
154 .ops = &pllc2_clk_ops,
155 .flags = CLK_ENABLE_ON_INIT,
156 .parent = &extal1_div2_clk,
157};
158
159struct clk *main_clks[] = {
160 &r_clk,
161 &extal1_clk,
162 &extal2_clk,
163 &extal1_div2_clk,
164 &extal2_div2_clk,
165 &extal2_div4_clk,
166 &pllc0_clk,
167 &pllc1_clk,
168 &pllc1_div2_clk,
169 &pllc2_clk,
170};
171
172static void div4_kick(struct clk *clk)
173{
174 unsigned long value;
175
176 /* set KICK bit in FRQCRB to update hardware setting */
177 value = __raw_readl(FRQCRB);
178 value |= (1 << 31);
179 __raw_writel(value, FRQCRB);
180}
181
182static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
183 24, 32, 36, 48, 0, 72, 96, 0 };
184
185static struct clk_div_mult_table div4_div_mult_table = {
186 .divisors = divisors,
187 .nr_divisors = ARRAY_SIZE(divisors),
188};
189
190static struct clk_div4_table div4_table = {
191 .div_mult_table = &div4_div_mult_table,
192 .kick = div4_kick,
193};
194
195enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR,
196 DIV4_ZTR, DIV4_ZT, DIV4_ZX, DIV4_HP,
197 DIV4_ISPB, DIV4_S, DIV4_ZB, DIV4_ZB3, DIV4_CP,
198 DIV4_DDRP, DIV4_NR };
199
200#define DIV4(_reg, _bit, _mask, _flags) \
201 SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
202
203struct clk div4_clks[DIV4_NR] = {
204 [DIV4_I] = DIV4(FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT),
205 [DIV4_ZG] = DIV4(FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT),
206 [DIV4_B] = DIV4(FRQCRA, 8, 0x6fff, CLK_ENABLE_ON_INIT),
207 [DIV4_M1] = DIV4(FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT),
208 [DIV4_CSIR] = DIV4(FRQCRA, 0, 0x6fff, 0),
209 [DIV4_ZTR] = DIV4(FRQCRB, 20, 0x6fff, 0),
210 [DIV4_ZT] = DIV4(FRQCRB, 16, 0x6fff, 0),
211 [DIV4_ZX] = DIV4(FRQCRB, 12, 0x6fff, 0),
212 [DIV4_HP] = DIV4(FRQCRB, 4, 0x6fff, 0),
213 [DIV4_ISPB] = DIV4(FRQCRC, 20, 0x6fff, 0),
214 [DIV4_S] = DIV4(FRQCRC, 12, 0x6fff, 0),
215 [DIV4_ZB] = DIV4(FRQCRC, 8, 0x6fff, 0),
216 [DIV4_ZB3] = DIV4(FRQCRC, 4, 0x6fff, 0),
217 [DIV4_CP] = DIV4(FRQCRC, 0, 0x6fff, 0),
218 [DIV4_DDRP] = DIV4(FRQCRD, 0, 0x677c, 0),
219};
220
221enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
222 DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
223 DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
224 DIV6_NR };
225
226struct clk div6_clks[DIV6_NR] = {
227 [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
228 [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
229 [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
230 [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0),
231 [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0),
232 [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0),
233 [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0),
234 [DIV6_SUB] = SH_CLK_DIV6(&extal2_clk, SUBCKCR, 0),
235 [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
236 [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
237 [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
238 [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
239 [DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0),
240 [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
241};
242
243enum { MSTP001,
244 MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101,
245 MSTP223,
246 MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
247 MSTP329, MSTP323, MSTP322, MSTP314, MSTP313,
248 MSTP415, MSTP410, MSTP411, MSTP406, MSTP403,
249 MSTP_NR };
250
251#define MSTP(_parent, _reg, _bit, _flags) \
252 SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
253
254static struct clk mstp_clks[MSTP_NR] = {
255 [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
256 [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
257 [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
258 [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
259 [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */
260 [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
261 [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
262 [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
263 [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
264 [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
265 [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
266 [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
267 [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
268 [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
269 [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
270 [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
271 [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
272 [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
273 [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
274 [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
275 [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
276 [MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
277 [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
278 [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
279 [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
280 [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
281};
282
283#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
284#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
285
286static struct clk_lookup lookups[] = {
287 /* main clocks */
288 CLKDEV_CON_ID("r_clk", &r_clk),
289 CLKDEV_CON_ID("extal1", &extal1_clk),
290 CLKDEV_CON_ID("extal2", &extal2_clk),
291 CLKDEV_CON_ID("extal1_div2_clk", &extal1_div2_clk),
292 CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
293 CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk),
294 CLKDEV_CON_ID("pllc0_clk", &pllc0_clk),
295 CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
296 CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
297 CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
298
299 /* DIV4 clocks */
300 CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
301 CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]),
302 CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
303 CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]),
304 CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]),
305 CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]),
306 CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
307 CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]),
308 CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
309 CLKDEV_CON_ID("ispb_clk", &div4_clks[DIV4_ISPB]),
310 CLKDEV_CON_ID("s_clk", &div4_clks[DIV4_S]),
311 CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
312 CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
313 CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
314 CLKDEV_CON_ID("ddrp_clk", &div4_clks[DIV4_DDRP]),
315
316 /* DIV6 clocks */
317 CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
318 CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
319 CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
320 CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
321 CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
322 CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]),
323 CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]),
324 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
325 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
326 CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
327 CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
328 CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
329 CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
330 CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),
331
332 /* MSTP32 clocks */
333 CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
334 CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP131]), /* VEU3 */
335 CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP130]), /* VEU2 */
336 CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP129]), /* VEU1 */
337 CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP128]), /* VEU0 */
338 CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
339 CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
340 CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
341 CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
342 CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
343 CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
344 CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
345 CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
346 CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
347 CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
348 CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
349 CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
350 CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
351 CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
352 CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */
353 CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */
354 CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
355 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
356 CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
357 CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
358 CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
359 CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
360 CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
361 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
362};
363
364void __init sh7372_clock_init(void)
365{
366 int k, ret = 0;
367
368 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
369 ret = clk_register(main_clks[k]);
370
371 if (!ret)
372 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
373
374 if (!ret)
375 ret = sh_clk_div6_register(div6_clks, DIV6_NR);
376
377 if (!ret)
378 ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
379
380 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
381
382 if (!ret)
383 clk_init();
384 else
385 panic("failed to setup sh7372 clocks\n");
386
387}