blob: 5218c34a9cc6b77994d1f51966679a9b2e5fee73 [file] [log] [blame]
Magnus Dammc793c1b2010-02-05 11:14:49 +00001/*
Magnus Damm4f0836b2010-05-20 14:49:28 +00002 * SH7367 clock framework support
Magnus Dammc793c1b2010-02-05 11:14:49 +00003 *
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; 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/init.h>
Magnus Dammc793c1b2010-02-05 11:14:49 +000020#include <linux/kernel.h>
Magnus Damm4f0836b2010-05-20 14:49:28 +000021#include <linux/io.h>
Magnus Damme47bb512010-05-12 14:21:24 +000022#include <linux/sh_clk.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010023#include <linux/clkdev.h>
Magnus Damm4f0836b2010-05-20 14:49:28 +000024#include <mach/common.h>
Magnus Dammc793c1b2010-02-05 11:14:49 +000025
Magnus Damm4f0836b2010-05-20 14:49:28 +000026/* SH7367 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 SCLKACR 0xe6150010
34#define SCLKBCR 0xe6150014
35#define SUBUSBCKCR 0xe6158080
36#define SPUCKCR 0xe6150084
37#define MSUCKCR 0xe6150088
38#define MVI3CKCR 0xe6150090
39#define VOUCKCR 0xe6150094
40#define MFCK1CR 0xe6150098
41#define MFCK2CR 0xe615009C
42#define PLLC1CR 0xe6150028
43#define PLLC2CR 0xe615002C
44#define RTMSTPCR0 0xe6158030
45#define RTMSTPCR2 0xe6158038
46#define SYMSTPCR0 0xe6158040
47#define SYMSTPCR2 0xe6158048
48#define CMMSTPCR0 0xe615804c
Magnus Dammc793c1b2010-02-05 11:14:49 +000049
Magnus Damm4f0836b2010-05-20 14:49:28 +000050/* Fixed 32 KHz root clock from EXTALR pin */
Magnus Dammc793c1b2010-02-05 11:14:49 +000051static struct clk r_clk = {
Magnus Damm4f0836b2010-05-20 14:49:28 +000052 .rate = 32768,
Magnus Dammc793c1b2010-02-05 11:14:49 +000053};
54
Magnus Damm4f0836b2010-05-20 14:49:28 +000055/*
56 * 26MHz default rate for the EXTALB1 root input clock.
57 * If needed, reset this with clk_set_rate() from the platform code.
58 */
59struct clk sh7367_extalb1_clk = {
60 .rate = 26666666,
Magnus Damm3a7b8022010-02-10 20:13:31 +090061};
62
Magnus Damm4f0836b2010-05-20 14:49:28 +000063/*
64 * 48MHz default rate for the EXTAL2 root input clock.
65 * If needed, reset this with clk_set_rate() from the platform code.
66 */
67struct clk sh7367_extal2_clk = {
68 .rate = 48000000,
Magnus Damm03fb2562010-02-16 10:48:15 +000069};
70
Magnus Damm4f0836b2010-05-20 14:49:28 +000071/* A fixed divide-by-2 block */
72static unsigned long div2_recalc(struct clk *clk)
73{
74 return clk->parent->rate / 2;
75}
76
77static struct clk_ops div2_clk_ops = {
78 .recalc = div2_recalc,
79};
80
81/* Divide extalb1 by two */
82static struct clk extalb1_div2_clk = {
83 .ops = &div2_clk_ops,
84 .parent = &sh7367_extalb1_clk,
85};
86
87/* Divide extal2 by two */
88static struct clk extal2_div2_clk = {
89 .ops = &div2_clk_ops,
90 .parent = &sh7367_extal2_clk,
91};
92
93/* PLLC1 */
94static unsigned long pllc1_recalc(struct clk *clk)
95{
96 unsigned long mult = 1;
97
98 if (__raw_readl(PLLC1CR) & (1 << 14))
99 mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2;
100
101 return clk->parent->rate * mult;
102}
103
104static struct clk_ops pllc1_clk_ops = {
105 .recalc = pllc1_recalc,
106};
107
108static struct clk pllc1_clk = {
109 .ops = &pllc1_clk_ops,
110 .flags = CLK_ENABLE_ON_INIT,
111 .parent = &extalb1_div2_clk,
112};
113
114/* Divide PLLC1 by two */
115static struct clk pllc1_div2_clk = {
116 .ops = &div2_clk_ops,
117 .parent = &pllc1_clk,
118};
119
120/* PLLC2 */
121static unsigned long pllc2_recalc(struct clk *clk)
122{
123 unsigned long mult = 1;
124
125 if (__raw_readl(PLLC2CR) & (1 << 31))
126 mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
127
128 return clk->parent->rate * mult;
129}
130
131static struct clk_ops pllc2_clk_ops = {
132 .recalc = pllc2_recalc,
133};
134
135static struct clk pllc2_clk = {
136 .ops = &pllc2_clk_ops,
137 .flags = CLK_ENABLE_ON_INIT,
138 .parent = &extalb1_div2_clk,
139};
140
141static struct clk *main_clks[] = {
142 &r_clk,
143 &sh7367_extalb1_clk,
144 &sh7367_extal2_clk,
145 &extalb1_div2_clk,
146 &extal2_div2_clk,
147 &pllc1_clk,
148 &pllc1_div2_clk,
149 &pllc2_clk,
150};
151
152static void div4_kick(struct clk *clk)
153{
154 unsigned long value;
155
156 /* set KICK bit in SYFRQCR to update hardware setting */
157 value = __raw_readl(SYFRQCR);
158 value |= (1 << 31);
159 __raw_writel(value, SYFRQCR);
160}
161
162static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
163 24, 32, 36, 48, 0, 72, 0, 0 };
164
165static struct clk_div_mult_table div4_div_mult_table = {
166 .divisors = divisors,
167 .nr_divisors = ARRAY_SIZE(divisors),
168};
169
170static struct clk_div4_table div4_table = {
171 .div_mult_table = &div4_div_mult_table,
172 .kick = div4_kick,
173};
174
175enum { DIV4_I, DIV4_G, DIV4_S, DIV4_B,
176 DIV4_ZX, DIV4_ZT, DIV4_Z, DIV4_ZD, DIV4_HP,
177 DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR };
178
179#define DIV4(_reg, _bit, _mask, _flags) \
180 SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
181
182static struct clk div4_clks[DIV4_NR] = {
183 [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT),
184 [DIV4_G] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT),
185 [DIV4_S] = DIV4(RTFRQCR, 12, 0x6fff, CLK_ENABLE_ON_INIT),
186 [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT),
187 [DIV4_ZX] = DIV4(SYFRQCR, 20, 0x6fff, 0),
188 [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0),
189 [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0),
190 [DIV4_ZD] = DIV4(SYFRQCR, 8, 0x6fff, 0),
191 [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0),
192 [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0),
193 [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0),
194 [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0),
195 [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0),
196};
197
198enum { DIV6_SUB, DIV6_SIUA, DIV6_SIUB, DIV6_MSU, DIV6_SPU,
199 DIV6_MVI3, DIV6_MF1, DIV6_MF2,
200 DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_VOU,
201 DIV6_NR };
202
203static struct clk div6_clks[DIV6_NR] = {
204 [DIV6_SUB] = SH_CLK_DIV6(&sh7367_extal2_clk, SUBUSBCKCR, 0),
205 [DIV6_SIUA] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKACR, 0),
206 [DIV6_SIUB] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKBCR, 0),
207 [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0),
208 [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
209 [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0),
210 [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0),
211 [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0),
212 [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
213 [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
214 [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
215 [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
216};
217
218enum { RTMSTP001,
219 RTMSTP231, RTMSTP230, RTMSTP229, RTMSTP228, RTMSTP226,
220 RTMSTP216, RTMSTP206, RTMSTP205, RTMSTP201,
221 SYMSTP023, SYMSTP007, SYMSTP006, SYMSTP004,
222 SYMSTP003, SYMSTP002, SYMSTP001, SYMSTP000,
223 SYMSTP231, SYMSTP229, SYMSTP225, SYMSTP223, SYMSTP222,
224 SYMSTP215, SYMSTP214, SYMSTP213, SYMSTP211,
225 CMMSTP003,
226 MSTP_NR };
227
228#define MSTP(_parent, _reg, _bit, _flags) \
229 SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
230
231static struct clk mstp_clks[MSTP_NR] = {
232 [RTMSTP001] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR0, 1, 0), /* IIC2 */
233 [RTMSTP231] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 31, 0), /* VEU3 */
234 [RTMSTP230] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 30, 0), /* VEU2 */
235 [RTMSTP229] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 29, 0), /* VEU1 */
236 [RTMSTP228] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 28, 0), /* VEU0 */
237 [RTMSTP226] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 26, 0), /* VEU2H */
238 [RTMSTP216] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR2, 16, 0), /* IIC0 */
239 [RTMSTP206] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 6, 0), /* JPU */
240 [RTMSTP205] = MSTP(&div6_clks[DIV6_VOU], RTMSTPCR2, 5, 0), /* VOU */
241 [RTMSTP201] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 1, 0), /* VPU */
242 [SYMSTP023] = MSTP(&div6_clks[DIV6_SPU], SYMSTPCR0, 23, 0), /* SPU1 */
243 [SYMSTP007] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 7, 0), /* SCIFA5 */
244 [SYMSTP006] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 6, 0), /* SCIFB */
245 [SYMSTP004] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 4, 0), /* SCIFA0 */
246 [SYMSTP003] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 3, 0), /* SCIFA1 */
247 [SYMSTP002] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 2, 0), /* SCIFA2 */
248 [SYMSTP001] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 1, 0), /* SCIFA3 */
249 [SYMSTP000] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 0, 0), /* SCIFA4 */
250 [SYMSTP231] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 31, 0), /* SIU */
251 [SYMSTP229] = MSTP(&r_clk, SYMSTPCR2, 29, 0), /* CMT10 */
252 [SYMSTP225] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 25, 0), /* IRDA */
253 [SYMSTP223] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 23, 0), /* IIC1 */
254 [SYMSTP222] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 22, 0), /* USBHS */
255 [SYMSTP215] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 15, 0), /* FLCTL */
256 [SYMSTP214] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 14, 0), /* SDHI0 */
257 [SYMSTP213] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 13, 0), /* SDHI1 */
258 [SYMSTP211] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 11, 0), /* SDHI2 */
259 [CMMSTP003] = MSTP(&r_clk, CMMSTPCR0, 3, 0), /* KEYSC */
260};
261
Magnus Dammc793c1b2010-02-05 11:14:49 +0000262static struct clk_lookup lookups[] = {
Magnus Damm4f0836b2010-05-20 14:49:28 +0000263 /* main clocks */
264 CLKDEV_CON_ID("r_clk", &r_clk),
265 CLKDEV_CON_ID("extalb1", &sh7367_extalb1_clk),
266 CLKDEV_CON_ID("extal2", &sh7367_extal2_clk),
267 CLKDEV_CON_ID("extalb1_div2_clk", &extalb1_div2_clk),
268 CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
269 CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
270 CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
271 CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
272
273 /* DIV4 clocks */
274 CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
275 CLKDEV_CON_ID("g_clk", &div4_clks[DIV4_G]),
276 CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
277 CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]),
278 CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
279 CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]),
280 CLKDEV_CON_ID("zd_clk", &div4_clks[DIV4_ZD]),
281 CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
282 CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]),
283 CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
284 CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
285 CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
286
287 /* DIV6 clocks */
288 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
289 CLKDEV_CON_ID("siua_clk", &div6_clks[DIV6_SIUA]),
290 CLKDEV_CON_ID("siub_clk", &div6_clks[DIV6_SIUB]),
291 CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]),
292 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
293 CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]),
294 CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]),
295 CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]),
296 CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
297 CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
298 CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
299 CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
300
301 /* MSTP32 clocks */
302 CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[RTMSTP001]), /* IIC2 */
303 CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[RTMSTP231]), /* VEU3 */
304 CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[RTMSTP230]), /* VEU2 */
305 CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[RTMSTP229]), /* VEU1 */
306 CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[RTMSTP228]), /* VEU0 */
307 CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[RTMSTP226]), /* VEU2H */
308 CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[RTMSTP216]), /* IIC0 */
309 CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[RTMSTP206]), /* JPU */
310 CLKDEV_DEV_ID("sh-vou", &mstp_clks[RTMSTP205]), /* VOU */
311 CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[RTMSTP201]), /* VPU */
312 CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[SYMSTP023]), /* SPU1 */
313 CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[SYMSTP007]), /* SCIFA5 */
314 CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[SYMSTP006]), /* SCIFB */
315 CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[SYMSTP004]), /* SCIFA0 */
316 CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[SYMSTP003]), /* SCIFA1 */
317 CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[SYMSTP002]), /* SCIFA2 */
318 CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */
319 CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */
320 CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */
Magnus Damm90e09a52010-10-13 07:29:31 +0000321 CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[SYMSTP229]), /* CMT10 */
Magnus Damm4f0836b2010-05-20 14:49:28 +0000322 CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */
323 CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */
324 CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */
325 CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[SYMSTP222]), /* USBHS */
326 CLKDEV_DEV_ID("sh_flctl", &mstp_clks[SYMSTP215]), /* FLCTL */
327 CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[SYMSTP214]), /* SDHI0 */
328 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[SYMSTP213]), /* SDHI1 */
329 CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[SYMSTP211]), /* SDHI2 */
330 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[CMMSTP003]), /* KEYSC */
Magnus Dammc793c1b2010-02-05 11:14:49 +0000331};
332
333void __init sh7367_clock_init(void)
334{
Magnus Damm4f0836b2010-05-20 14:49:28 +0000335 int k, ret = 0;
Magnus Dammc793c1b2010-02-05 11:14:49 +0000336
Magnus Damm4f0836b2010-05-20 14:49:28 +0000337 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
338 ret = clk_register(main_clks[k]);
339
340 if (!ret)
341 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
342
343 if (!ret)
344 ret = sh_clk_div6_register(div6_clks, DIV6_NR);
345
346 if (!ret)
347 ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
348
349 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
350
351 if (!ret)
352 clk_init();
353 else
354 panic("failed to setup sh7367 clocks\n");
Magnus Dammc793c1b2010-02-05 11:14:49 +0000355}