blob: b8480d19e1c8400a8014a5e0cd2e7b22d33df93f [file] [log] [blame]
Magnus Damm0163acf2010-05-21 05:19:34 +00001/*
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>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010023#include <linux/clkdev.h>
Magnus Damm0163acf2010-05-21 05:19:34 +000024#include <mach/common.h>
Magnus Damm0163acf2010-05-21 05:19:34 +000025
26/* SH7377 registers */
Arnd Bergmann0a4b04d2012-09-14 20:08:08 +000027#define RTFRQCR IOMEM(0xe6150000)
28#define SYFRQCR IOMEM(0xe6150004)
29#define CMFRQCR IOMEM(0xe61500E0)
30#define VCLKCR1 IOMEM(0xe6150008)
31#define VCLKCR2 IOMEM(0xe615000C)
32#define VCLKCR3 IOMEM(0xe615001C)
33#define FMSICKCR IOMEM(0xe6150010)
34#define FMSOCKCR IOMEM(0xe6150014)
35#define FSICKCR IOMEM(0xe6150018)
36#define PLLC1CR IOMEM(0xe6150028)
37#define PLLC2CR IOMEM(0xe615002C)
38#define SUBUSBCKCR IOMEM(0xe6150080)
39#define SPUCKCR IOMEM(0xe6150084)
40#define MSUCKCR IOMEM(0xe6150088)
41#define MVI3CKCR IOMEM(0xe6150090)
42#define HDMICKCR IOMEM(0xe6150094)
43#define MFCK1CR IOMEM(0xe6150098)
44#define MFCK2CR IOMEM(0xe615009C)
45#define DSITCKCR IOMEM(0xe6150060)
46#define DSIPCKCR IOMEM(0xe6150064)
47#define SMSTPCR0 IOMEM(0xe6150130)
48#define SMSTPCR1 IOMEM(0xe6150134)
49#define SMSTPCR2 IOMEM(0xe6150138)
50#define SMSTPCR3 IOMEM(0xe615013C)
51#define SMSTPCR4 IOMEM(0xe6150140)
Magnus Damm0163acf2010-05-21 05:19:34 +000052
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
Magnus Damm9c8c7ab2012-02-29 22:16:36 +090080static struct sh_clk_ops div2_clk_ops = {
Magnus Damm0163acf2010-05-21 05:19:34 +000081 .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
Magnus Damm9c8c7ab2012-02-29 22:16:36 +0900113static struct sh_clk_ops pllc1_clk_ops = {
Magnus Damm0163acf2010-05-21 05:19:34 +0000114 .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
Magnus Damm9c8c7ab2012-02-29 22:16:36 +0900140static struct sh_clk_ops pllc2_clk_ops = {
Magnus Damm0163acf2010-05-21 05:19:34 +0000141 .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
Magnus Damm0163acf2010-05-21 05:19:34 +0000270static struct clk_lookup lookups[] = {
271 /* main clocks */
272 CLKDEV_CON_ID("r_clk", &r_clk),
273 CLKDEV_CON_ID("extalc1", &sh7377_extalc1_clk),
274 CLKDEV_CON_ID("extal2", &sh7377_extal2_clk),
275 CLKDEV_CON_ID("extalc1_div2_clk", &extalc1_div2_clk),
276 CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
277 CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk),
278 CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
279 CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
280 CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
281
282 /* DIV4 clocks */
283 CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
284 CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]),
285 CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
286 CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]),
287 CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]),
288 CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]),
289 CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
290 CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]),
291 CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
292 CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]),
293 CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
294 CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
295 CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
296
297 /* DIV6 clocks */
298 CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
299 CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
300 CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
301 CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
302 CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
303 CLKDEV_CON_ID("fsi_clk", &div6_clks[DIV6_FSI]),
304 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
305 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
306 CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]),
307 CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]),
308 CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
309 CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]),
310 CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]),
311 CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
312 CLKDEV_CON_ID("dsip_clk", &div6_clks[DIV6_DSIP]),
313
314 /* MSTP32 clocks */
315 CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
316 CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
317 CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
318 CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
319 CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */
320 CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
321 CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
322 CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
323 CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
324 CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
325 CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
326 CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP206]), /* SCIFB */
327 CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
328 CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
329 CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
330 CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
331 CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
332 CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
Magnus Damm90e09a52010-10-13 07:29:31 +0000333 CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
Magnus Damm0163acf2010-05-21 05:19:34 +0000334 CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */
335 CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
336 CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */
337 CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USBHS */
338 CLKDEV_DEV_ID("sh_flctl", &mstp_clks[MSTP315]), /* FLCTL */
339 CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
340 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
341 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
342};
343
344void __init sh7377_clock_init(void)
345{
346 int k, ret = 0;
347
348 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
349 ret = clk_register(main_clks[k]);
350
351 if (!ret)
352 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
353
354 if (!ret)
355 ret = sh_clk_div6_register(div6_clks, DIV6_NR);
356
357 if (!ret)
Nobuhiro Iwamatsu64e9de22012-06-27 09:59:00 +0900358 ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
Magnus Damm0163acf2010-05-21 05:19:34 +0000359
360 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
361
362 if (!ret)
Magnus Damm6b6a4c02012-02-29 21:41:30 +0900363 shmobile_clk_init();
Magnus Damm0163acf2010-05-21 05:19:34 +0000364 else
365 panic("failed to setup sh7377 clocks\n");
366}