aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/clock-sh7377.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-shmobile/clock-sh7377.c')
-rw-r--r--arch/arm/mach-shmobile/clock-sh7377.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c
new file mode 100644
index 000000000000..e007c28cf0a8
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-sh7377.c
@@ -0,0 +1,369 @@
1/*
2 * SH7377 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/io.h>
22#include <linux/sh_clk.h>
23#include <mach/common.h>
24#include <asm/clkdev.h>
25
26/* SH7377 registers */
27#define RTFRQCR 0xe6150000
28#define SYFRQCR 0xe6150004
29#define CMFRQCR 0xe61500E0
30#define VCLKCR1 0xe6150008
31#define VCLKCR2 0xe615000C
32#define VCLKCR3 0xe615001C
33#define FMSICKCR 0xe6150010
34#define FMSOCKCR 0xe6150014
35#define FSICKCR 0xe6150018
36#define PLLC1CR 0xe6150028
37#define PLLC2CR 0xe615002C
38#define SUBUSBCKCR 0xe6150080
39#define SPUCKCR 0xe6150084
40#define MSUCKCR 0xe6150088
41#define MVI3CKCR 0xe6150090
42#define HDMICKCR 0xe6150094
43#define MFCK1CR 0xe6150098
44#define MFCK2CR 0xe615009C
45#define DSITCKCR 0xe6150060
46#define DSIPCKCR 0xe6150064
47#define SMSTPCR0 0xe6150130
48#define SMSTPCR1 0xe6150134
49#define SMSTPCR2 0xe6150138
50#define SMSTPCR3 0xe615013C
51#define SMSTPCR4 0xe6150140
52
53/* Fixed 32 KHz root clock from EXTALR pin */
54static struct clk r_clk = {
55 .rate = 32768,
56};
57
58/*
59 * 26MHz default rate for the EXTALC1 root input clock.
60 * If needed, reset this with clk_set_rate() from the platform code.
61 */
62struct clk sh7377_extalc1_clk = {
63 .rate = 26666666,
64};
65
66/*
67 * 48MHz default rate for the EXTAL2 root input clock.
68 * If needed, reset this with clk_set_rate() from the platform code.
69 */
70struct clk sh7377_extal2_clk = {
71 .rate = 48000000,
72};
73
74/* A fixed divide-by-2 block */
75static unsigned long div2_recalc(struct clk *clk)
76{
77 return clk->parent->rate / 2;
78}
79
80static struct clk_ops div2_clk_ops = {
81 .recalc = div2_recalc,
82};
83
84/* Divide extalc1 by two */
85static struct clk extalc1_div2_clk = {
86 .ops = &div2_clk_ops,
87 .parent = &sh7377_extalc1_clk,
88};
89
90/* Divide extal2 by two */
91static struct clk extal2_div2_clk = {
92 .ops = &div2_clk_ops,
93 .parent = &sh7377_extal2_clk,
94};
95
96/* Divide extal2 by four */
97static struct clk extal2_div4_clk = {
98 .ops = &div2_clk_ops,
99 .parent = &extal2_div2_clk,
100};
101
102/* PLLC1 */
103static unsigned long pllc1_recalc(struct clk *clk)
104{
105 unsigned long mult = 1;
106
107 if (__raw_readl(PLLC1CR) & (1 << 14))
108 mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2;
109
110 return clk->parent->rate * mult;
111}
112
113static struct clk_ops pllc1_clk_ops = {
114 .recalc = pllc1_recalc,
115};
116
117static struct clk pllc1_clk = {
118 .ops = &pllc1_clk_ops,
119 .flags = CLK_ENABLE_ON_INIT,
120 .parent = &extalc1_div2_clk,
121};
122
123/* Divide PLLC1 by two */
124static struct clk pllc1_div2_clk = {
125 .ops = &div2_clk_ops,
126 .parent = &pllc1_clk,
127};
128
129/* PLLC2 */
130static unsigned long pllc2_recalc(struct clk *clk)
131{
132 unsigned long mult = 1;
133
134 if (__raw_readl(PLLC2CR) & (1 << 31))
135 mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
136
137 return clk->parent->rate * mult;
138}
139
140static struct clk_ops pllc2_clk_ops = {
141 .recalc = pllc2_recalc,
142};
143
144static struct clk pllc2_clk = {
145 .ops = &pllc2_clk_ops,
146 .flags = CLK_ENABLE_ON_INIT,
147 .parent = &extalc1_div2_clk,
148};
149
150static struct clk *main_clks[] = {
151 &r_clk,
152 &sh7377_extalc1_clk,
153 &sh7377_extal2_clk,
154 &extalc1_div2_clk,
155 &extal2_div2_clk,
156 &extal2_div4_clk,
157 &pllc1_clk,
158 &pllc1_div2_clk,
159 &pllc2_clk,
160};
161
162static void div4_kick(struct clk *clk)
163{
164 unsigned long value;
165
166 /* set KICK bit in SYFRQCR to update hardware setting */
167 value = __raw_readl(SYFRQCR);
168 value |= (1 << 31);
169 __raw_writel(value, SYFRQCR);
170}
171
172static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
173 24, 32, 36, 48, 0, 72, 96, 0 };
174
175static struct clk_div_mult_table div4_div_mult_table = {
176 .divisors = divisors,
177 .nr_divisors = ARRAY_SIZE(divisors),
178};
179
180static struct clk_div4_table div4_table = {
181 .div_mult_table = &div4_div_mult_table,
182 .kick = div4_kick,
183};
184
185enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR,
186 DIV4_ZTR, DIV4_ZT, DIV4_Z, DIV4_HP,
187 DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR };
188
189#define DIV4(_reg, _bit, _mask, _flags) \
190 SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
191
192static struct clk div4_clks[DIV4_NR] = {
193 [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT),
194 [DIV4_ZG] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT),
195 [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT),
196 [DIV4_M1] = DIV4(RTFRQCR, 4, 0x6fff, CLK_ENABLE_ON_INIT),
197 [DIV4_CSIR] = DIV4(RTFRQCR, 0, 0x6fff, 0),
198 [DIV4_ZTR] = DIV4(SYFRQCR, 20, 0x6fff, 0),
199 [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0),
200 [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0),
201 [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0),
202 [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0),
203 [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0),
204 [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0),
205 [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0),
206};
207
208enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
209 DIV6_FSI, DIV6_SUB, DIV6_SPU, DIV6_MSU, DIV6_MVI3, DIV6_HDMI,
210 DIV6_MF1, DIV6_MF2, DIV6_DSIT, DIV6_DSIP,
211 DIV6_NR };
212
213static struct clk div6_clks[] = {
214 [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
215 [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
216 [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
217 [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0),
218 [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0),
219 [DIV6_FSI] = SH_CLK_DIV6(&pllc1_div2_clk, FSICKCR, 0),
220 [DIV6_SUB] = SH_CLK_DIV6(&sh7377_extal2_clk, SUBUSBCKCR, 0),
221 [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
222 [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0),
223 [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0),
224 [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
225 [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0),
226 [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0),
227 [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
228 [DIV6_DSIP] = SH_CLK_DIV6(&pllc1_div2_clk, DSIPCKCR, 0),
229};
230
231enum { MSTP001,
232 MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101,
233 MSTP223, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
234 MSTP331, MSTP329, MSTP325, MSTP323, MSTP322,
235 MSTP315, MSTP314, MSTP313,
236 MSTP403,
237 MSTP_NR };
238
239#define MSTP(_parent, _reg, _bit, _flags) \
240 SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
241
242static struct clk mstp_clks[] = {
243 [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
244 [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
245 [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
246 [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
247 [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */
248 [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
249 [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
250 [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
251 [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
252 [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
253 [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
254 [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
255 [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
256 [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
257 [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
258 [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
259 [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
260 [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
261 [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IRDA */
262 [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
263 [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
264 [MSTP315] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 15, 0), /* FLCTL */
265 [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
266 [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
267 [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
268};
269
270#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
271#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
272
273static struct clk_lookup lookups[] = {
274 /* main clocks */
275 CLKDEV_CON_ID("r_clk", &r_clk),
276 CLKDEV_CON_ID("extalc1", &sh7377_extalc1_clk),
277 CLKDEV_CON_ID("extal2", &sh7377_extal2_clk),
278 CLKDEV_CON_ID("extalc1_div2_clk", &extalc1_div2_clk),
279 CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
280 CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk),
281 CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
282 CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
283 CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
284
285 /* DIV4 clocks */
286 CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
287 CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]),
288 CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
289 CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]),
290 CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]),
291 CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]),
292 CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
293 CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]),
294 CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
295 CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]),
296 CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
297 CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
298 CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
299
300 /* DIV6 clocks */
301 CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
302 CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
303 CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
304 CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
305 CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
306 CLKDEV_CON_ID("fsi_clk", &div6_clks[DIV6_FSI]),
307 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
308 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
309 CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]),
310 CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]),
311 CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
312 CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]),
313 CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]),
314 CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
315 CLKDEV_CON_ID("dsip_clk", &div6_clks[DIV6_DSIP]),
316
317 /* MSTP32 clocks */
318 CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
319 CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
320 CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
321 CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
322 CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */
323 CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
324 CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
325 CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
326 CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
327 CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
328 CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
329 CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP206]), /* SCIFB */
330 CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
331 CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
332 CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
333 CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
334 CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
335 CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
336 CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
337 CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */
338 CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
339 CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */
340 CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USBHS */
341 CLKDEV_DEV_ID("sh_flctl", &mstp_clks[MSTP315]), /* FLCTL */
342 CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
343 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
344 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
345};
346
347void __init sh7377_clock_init(void)
348{
349 int k, ret = 0;
350
351 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
352 ret = clk_register(main_clks[k]);
353
354 if (!ret)
355 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
356
357 if (!ret)
358 ret = sh_clk_div6_register(div6_clks, DIV6_NR);
359
360 if (!ret)
361 ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
362
363 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
364
365 if (!ret)
366 clk_init();
367 else
368 panic("failed to setup sh7377 clocks\n");
369}