1bc49b6eaSMagnus Damm /*
2bc49b6eaSMagnus Damm  * arch/sh/kernel/cpu/sh4a/clock-sh7343.c
3bc49b6eaSMagnus Damm  *
4bc49b6eaSMagnus Damm  * SH7343 clock framework support
5bc49b6eaSMagnus Damm  *
6bc49b6eaSMagnus Damm  * Copyright (C) 2009 Magnus Damm
7bc49b6eaSMagnus Damm  *
8bc49b6eaSMagnus Damm  * This program is free software; you can redistribute it and/or modify
9bc49b6eaSMagnus Damm  * it under the terms of the GNU General Public License as published by
10bc49b6eaSMagnus Damm  * the Free Software Foundation; either version 2 of the License
11bc49b6eaSMagnus Damm  *
12bc49b6eaSMagnus Damm  * This program is distributed in the hope that it will be useful,
13bc49b6eaSMagnus Damm  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14bc49b6eaSMagnus Damm  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15bc49b6eaSMagnus Damm  * GNU General Public License for more details.
16bc49b6eaSMagnus Damm  *
17bc49b6eaSMagnus Damm  * You should have received a copy of the GNU General Public License
18bc49b6eaSMagnus Damm  * along with this program; if not, write to the Free Software
19bc49b6eaSMagnus Damm  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20bc49b6eaSMagnus Damm  */
21bc49b6eaSMagnus Damm #include <linux/init.h>
22bc49b6eaSMagnus Damm #include <linux/kernel.h>
23bc49b6eaSMagnus Damm #include <linux/io.h>
24098ec49bSMagnus Damm #include <asm/clkdev.h>
25bc49b6eaSMagnus Damm #include <asm/clock.h>
26bc49b6eaSMagnus Damm 
27bc49b6eaSMagnus Damm /* SH7343 registers */
28bc49b6eaSMagnus Damm #define FRQCR		0xa4150000
29bc49b6eaSMagnus Damm #define VCLKCR		0xa4150004
30bc49b6eaSMagnus Damm #define SCLKACR		0xa4150008
31bc49b6eaSMagnus Damm #define SCLKBCR		0xa415000c
32bc49b6eaSMagnus Damm #define PLLCR		0xa4150024
33bc49b6eaSMagnus Damm #define MSTPCR0		0xa4150030
34bc49b6eaSMagnus Damm #define MSTPCR1		0xa4150034
35bc49b6eaSMagnus Damm #define MSTPCR2		0xa4150038
36bc49b6eaSMagnus Damm #define DLLFRQ		0xa4150050
37bc49b6eaSMagnus Damm 
38bc49b6eaSMagnus Damm /* Fixed 32 KHz root clock for RTC and Power Management purposes */
39bc49b6eaSMagnus Damm static struct clk r_clk = {
40bc49b6eaSMagnus Damm 	.name           = "rclk",
41bc49b6eaSMagnus Damm 	.id             = -1,
42bc49b6eaSMagnus Damm 	.rate           = 32768,
43bc49b6eaSMagnus Damm };
44bc49b6eaSMagnus Damm 
45bc49b6eaSMagnus Damm /*
46bc49b6eaSMagnus Damm  * Default rate for the root input clock, reset this with clk_set_rate()
47bc49b6eaSMagnus Damm  * from the platform code.
48bc49b6eaSMagnus Damm  */
49bc49b6eaSMagnus Damm struct clk extal_clk = {
50bc49b6eaSMagnus Damm 	.name		= "extal",
51bc49b6eaSMagnus Damm 	.id		= -1,
52bc49b6eaSMagnus Damm 	.rate		= 33333333,
53bc49b6eaSMagnus Damm };
54bc49b6eaSMagnus Damm 
55bc49b6eaSMagnus Damm /* The dll block multiplies the 32khz r_clk, may be used instead of extal */
56bc49b6eaSMagnus Damm static unsigned long dll_recalc(struct clk *clk)
57bc49b6eaSMagnus Damm {
58bc49b6eaSMagnus Damm 	unsigned long mult;
59bc49b6eaSMagnus Damm 
60bc49b6eaSMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
61bc49b6eaSMagnus Damm 		mult = __raw_readl(DLLFRQ);
62bc49b6eaSMagnus Damm 	else
63bc49b6eaSMagnus Damm 		mult = 0;
64bc49b6eaSMagnus Damm 
65bc49b6eaSMagnus Damm 	return clk->parent->rate * mult;
66bc49b6eaSMagnus Damm }
67bc49b6eaSMagnus Damm 
68bc49b6eaSMagnus Damm static struct clk_ops dll_clk_ops = {
69bc49b6eaSMagnus Damm 	.recalc		= dll_recalc,
70bc49b6eaSMagnus Damm };
71bc49b6eaSMagnus Damm 
72bc49b6eaSMagnus Damm static struct clk dll_clk = {
73bc49b6eaSMagnus Damm 	.name           = "dll_clk",
74bc49b6eaSMagnus Damm 	.id             = -1,
75bc49b6eaSMagnus Damm 	.ops		= &dll_clk_ops,
76bc49b6eaSMagnus Damm 	.parent		= &r_clk,
77bc49b6eaSMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
78bc49b6eaSMagnus Damm };
79bc49b6eaSMagnus Damm 
80bc49b6eaSMagnus Damm static unsigned long pll_recalc(struct clk *clk)
81bc49b6eaSMagnus Damm {
82bc49b6eaSMagnus Damm 	unsigned long mult = 1;
83bc49b6eaSMagnus Damm 
84bc49b6eaSMagnus Damm 	if (__raw_readl(PLLCR) & 0x4000)
85bc49b6eaSMagnus Damm 		mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
86bc49b6eaSMagnus Damm 
87bc49b6eaSMagnus Damm 	return clk->parent->rate * mult;
88bc49b6eaSMagnus Damm }
89bc49b6eaSMagnus Damm 
90bc49b6eaSMagnus Damm static struct clk_ops pll_clk_ops = {
91bc49b6eaSMagnus Damm 	.recalc		= pll_recalc,
92bc49b6eaSMagnus Damm };
93bc49b6eaSMagnus Damm 
94bc49b6eaSMagnus Damm static struct clk pll_clk = {
95bc49b6eaSMagnus Damm 	.name		= "pll_clk",
96bc49b6eaSMagnus Damm 	.id		= -1,
97bc49b6eaSMagnus Damm 	.ops		= &pll_clk_ops,
98bc49b6eaSMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
99bc49b6eaSMagnus Damm };
100bc49b6eaSMagnus Damm 
101bc49b6eaSMagnus Damm struct clk *main_clks[] = {
102bc49b6eaSMagnus Damm 	&r_clk,
103bc49b6eaSMagnus Damm 	&extal_clk,
104bc49b6eaSMagnus Damm 	&dll_clk,
105bc49b6eaSMagnus Damm 	&pll_clk,
106bc49b6eaSMagnus Damm };
107bc49b6eaSMagnus Damm 
108bc49b6eaSMagnus Damm static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
109bc49b6eaSMagnus Damm static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
110bc49b6eaSMagnus Damm 
1110a5f337eSMagnus Damm static struct clk_div_mult_table div4_div_mult_table = {
112bc49b6eaSMagnus Damm 	.divisors = divisors,
113bc49b6eaSMagnus Damm 	.nr_divisors = ARRAY_SIZE(divisors),
114bc49b6eaSMagnus Damm 	.multipliers = multipliers,
115bc49b6eaSMagnus Damm 	.nr_multipliers = ARRAY_SIZE(multipliers),
116bc49b6eaSMagnus Damm };
117bc49b6eaSMagnus Damm 
1180a5f337eSMagnus Damm static struct clk_div4_table div4_table = {
1190a5f337eSMagnus Damm 	.div_mult_table = &div4_div_mult_table,
1200a5f337eSMagnus Damm };
1210a5f337eSMagnus Damm 
122bc49b6eaSMagnus Damm enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
123bc49b6eaSMagnus Damm        DIV4_SIUA, DIV4_SIUB, DIV4_NR };
124bc49b6eaSMagnus Damm 
125bc49b6eaSMagnus Damm #define DIV4(_str, _reg, _bit, _mask, _flags) \
126bc49b6eaSMagnus Damm   SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
127bc49b6eaSMagnus Damm 
128bc49b6eaSMagnus Damm struct clk div4_clks[DIV4_NR] = {
129bc49b6eaSMagnus Damm 	[DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fff, CLK_ENABLE_ON_INIT),
130bc49b6eaSMagnus Damm 	[DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
131bc49b6eaSMagnus Damm 	[DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
132bc49b6eaSMagnus Damm 	[DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
133bc49b6eaSMagnus Damm 	[DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
134bc49b6eaSMagnus Damm 	[DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
135bc49b6eaSMagnus Damm 	[DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
136bc49b6eaSMagnus Damm 	[DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
137bc49b6eaSMagnus Damm };
138bc49b6eaSMagnus Damm 
139098ec49bSMagnus Damm enum { DIV6_V, DIV6_NR };
140098ec49bSMagnus Damm 
141098ec49bSMagnus Damm struct clk div6_clks[DIV6_NR] = {
1429e1985e1SMagnus Damm 	[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
143bc49b6eaSMagnus Damm };
144bc49b6eaSMagnus Damm 
145bc49b6eaSMagnus Damm #define MSTP(_str, _parent, _reg, _bit, _flags) \
146bc49b6eaSMagnus Damm   SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
147bc49b6eaSMagnus Damm 
148e8b96918SMagnus Damm enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
149e8b96918SMagnus Damm        MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
150e8b96918SMagnus Damm        MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
151e8b96918SMagnus Damm        MSTP007, MSTP006, MSTP005, MSTP004, MSTP003, MSTP002, MSTP001,
152e8b96918SMagnus Damm        MSTP109, MSTP108, MSTP100,
153e8b96918SMagnus Damm        MSTP225, MSTP224, MSTP218, MSTP217, MSTP216,
154e8b96918SMagnus Damm        MSTP214, MSTP213, MSTP212, MSTP211, MSTP208,
155e8b96918SMagnus Damm        MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
156e8b96918SMagnus Damm        MSTP_NR };
157bc49b6eaSMagnus Damm 
158e8b96918SMagnus Damm static struct clk mstp_clks[MSTP_NR] = {
159e8b96918SMagnus Damm 	[MSTP031] = MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
160e8b96918SMagnus Damm 	[MSTP030] = MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
161e8b96918SMagnus Damm 	[MSTP029] = MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
162e8b96918SMagnus Damm 	[MSTP028] = MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
163e8b96918SMagnus Damm 	[MSTP026] = MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
164e8b96918SMagnus Damm 	[MSTP023] = MSTP("intc3", &div4_clks[DIV4_P], MSTPCR0, 23, 0),
165e8b96918SMagnus Damm 	[MSTP022] = MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 0),
166e8b96918SMagnus Damm 	[MSTP021] = MSTP("dmac0", &div4_clks[DIV4_P], MSTPCR0, 21, 0),
167e8b96918SMagnus Damm 	[MSTP020] = MSTP("sh0", &div4_clks[DIV4_P], MSTPCR0, 20, 0),
168e8b96918SMagnus Damm 	[MSTP019] = MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0),
169e8b96918SMagnus Damm 	[MSTP017] = MSTP("ubc0", &div4_clks[DIV4_P], MSTPCR0, 17, 0),
170e8b96918SMagnus Damm 	[MSTP015] = MSTP("tmu_fck", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
171e8b96918SMagnus Damm 	[MSTP014] = MSTP("cmt_fck", &r_clk, MSTPCR0, 14, 0),
172e8b96918SMagnus Damm 	[MSTP013] = MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
173e8b96918SMagnus Damm 	[MSTP011] = MSTP("mfi0", &div4_clks[DIV4_P], MSTPCR0, 11, 0),
174e8b96918SMagnus Damm 	[MSTP010] = MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
175e8b96918SMagnus Damm 	[MSTP007] = SH_CLK_MSTP32("sci_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 7, 0),
176e8b96918SMagnus Damm 	[MSTP006] = SH_CLK_MSTP32("sci_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 6, 0),
177e8b96918SMagnus Damm 	[MSTP005] = SH_CLK_MSTP32("sci_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 5, 0),
178e8b96918SMagnus Damm 	[MSTP004] = SH_CLK_MSTP32("sci_fck", 3, &div4_clks[DIV4_P], MSTPCR0, 4, 0),
179e8b96918SMagnus Damm 	[MSTP003] = MSTP("sio0", &div4_clks[DIV4_P], MSTPCR0, 3, 0),
180e8b96918SMagnus Damm 	[MSTP002] = MSTP("siof0", &div4_clks[DIV4_P], MSTPCR0, 2, 0),
181e8b96918SMagnus Damm 	[MSTP001] = MSTP("siof1", &div4_clks[DIV4_P], MSTPCR0, 1, 0),
182bc49b6eaSMagnus Damm 
183e8b96918SMagnus Damm 	[MSTP109] = MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
184e8b96918SMagnus Damm 	[MSTP108] = MSTP("i2c1", &div4_clks[DIV4_P], MSTPCR1, 8, 0),
185e8b96918SMagnus Damm 
186e8b96918SMagnus Damm 	[MSTP225] = MSTP("tpu0", &div4_clks[DIV4_P], MSTPCR2, 25, 0),
187e8b96918SMagnus Damm 	[MSTP224] = MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0),
188e8b96918SMagnus Damm 	[MSTP218] = MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
189e8b96918SMagnus Damm 	[MSTP217] = MSTP("mmcif0", &div4_clks[DIV4_P], MSTPCR2, 17, 0),
190e8b96918SMagnus Damm 	[MSTP216] = MSTP("sim0", &div4_clks[DIV4_P], MSTPCR2, 16, 0),
191e8b96918SMagnus Damm 	[MSTP214] = MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
192e8b96918SMagnus Damm 	[MSTP213] = MSTP("tsif0", &div4_clks[DIV4_P], MSTPCR2, 13, 0),
193e8b96918SMagnus Damm 	[MSTP212] = MSTP("s3d40", &div4_clks[DIV4_P], MSTPCR2, 12, 0),
194e8b96918SMagnus Damm 	[MSTP211] = MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
195e8b96918SMagnus Damm 	[MSTP208] = MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
196e8b96918SMagnus Damm 	[MSTP206] = MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
197e8b96918SMagnus Damm 	[MSTP205] = MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
198e8b96918SMagnus Damm 	[MSTP204] = MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
199e8b96918SMagnus Damm 	[MSTP203] = MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
200e8b96918SMagnus Damm 	[MSTP202] = MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
201e8b96918SMagnus Damm 	[MSTP201] = MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
202e8b96918SMagnus Damm 	[MSTP200] = MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
203bc49b6eaSMagnus Damm };
204bc49b6eaSMagnus Damm 
205098ec49bSMagnus Damm #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
206098ec49bSMagnus Damm 
207098ec49bSMagnus Damm static struct clk_lookup lookups[] = {
208098ec49bSMagnus Damm 	/* DIV6 clocks */
209098ec49bSMagnus Damm 	CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
210098ec49bSMagnus Damm };
211098ec49bSMagnus Damm 
212bc49b6eaSMagnus Damm int __init arch_clk_init(void)
213bc49b6eaSMagnus Damm {
214bc49b6eaSMagnus Damm 	int k, ret = 0;
215bc49b6eaSMagnus Damm 
216bc49b6eaSMagnus Damm 	/* autodetect extal or dll configuration */
217bc49b6eaSMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
218bc49b6eaSMagnus Damm 		pll_clk.parent = &dll_clk;
219bc49b6eaSMagnus Damm 	else
220bc49b6eaSMagnus Damm 		pll_clk.parent = &extal_clk;
221bc49b6eaSMagnus Damm 
222bc49b6eaSMagnus Damm 	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
223bc49b6eaSMagnus Damm 		ret = clk_register(main_clks[k]);
224bc49b6eaSMagnus Damm 
225098ec49bSMagnus Damm 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
226098ec49bSMagnus Damm 
227bc49b6eaSMagnus Damm 	if (!ret)
228bc49b6eaSMagnus Damm 		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
229bc49b6eaSMagnus Damm 
230bc49b6eaSMagnus Damm 	if (!ret)
231098ec49bSMagnus Damm 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
232bc49b6eaSMagnus Damm 
233bc49b6eaSMagnus Damm 	if (!ret)
234e8b96918SMagnus Damm 		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
235bc49b6eaSMagnus Damm 
236bc49b6eaSMagnus Damm 	return ret;
237bc49b6eaSMagnus Damm }
238