14ed37394SMagnus Damm /*
24ed37394SMagnus Damm  * arch/sh/kernel/cpu/sh4a/clock-sh7366.c
34ed37394SMagnus Damm  *
44ed37394SMagnus Damm  * SH7366 clock framework support
54ed37394SMagnus Damm  *
64ed37394SMagnus Damm  * Copyright (C) 2009 Magnus Damm
74ed37394SMagnus Damm  *
84ed37394SMagnus Damm  * This program is free software; you can redistribute it and/or modify
94ed37394SMagnus Damm  * it under the terms of the GNU General Public License as published by
104ed37394SMagnus Damm  * the Free Software Foundation; either version 2 of the License
114ed37394SMagnus Damm  *
124ed37394SMagnus Damm  * This program is distributed in the hope that it will be useful,
134ed37394SMagnus Damm  * but WITHOUT ANY WARRANTY; without even the implied warranty of
144ed37394SMagnus Damm  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154ed37394SMagnus Damm  * GNU General Public License for more details.
164ed37394SMagnus Damm  *
174ed37394SMagnus Damm  * You should have received a copy of the GNU General Public License
184ed37394SMagnus Damm  * along with this program; if not, write to the Free Software
194ed37394SMagnus Damm  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
204ed37394SMagnus Damm  */
214ed37394SMagnus Damm #include <linux/init.h>
224ed37394SMagnus Damm #include <linux/kernel.h>
234ed37394SMagnus Damm #include <linux/io.h>
24098ec49bSMagnus Damm #include <asm/clkdev.h>
254ed37394SMagnus Damm #include <asm/clock.h>
264ed37394SMagnus Damm 
274ed37394SMagnus Damm /* SH7366 registers */
284ed37394SMagnus Damm #define FRQCR		0xa4150000
294ed37394SMagnus Damm #define VCLKCR		0xa4150004
304ed37394SMagnus Damm #define SCLKACR		0xa4150008
314ed37394SMagnus Damm #define SCLKBCR		0xa415000c
324ed37394SMagnus Damm #define PLLCR		0xa4150024
334ed37394SMagnus Damm #define MSTPCR0		0xa4150030
344ed37394SMagnus Damm #define MSTPCR1		0xa4150034
354ed37394SMagnus Damm #define MSTPCR2		0xa4150038
364ed37394SMagnus Damm #define DLLFRQ		0xa4150050
374ed37394SMagnus Damm 
384ed37394SMagnus Damm /* Fixed 32 KHz root clock for RTC and Power Management purposes */
394ed37394SMagnus Damm static struct clk r_clk = {
404ed37394SMagnus Damm 	.name           = "rclk",
414ed37394SMagnus Damm 	.id             = -1,
424ed37394SMagnus Damm 	.rate           = 32768,
434ed37394SMagnus Damm };
444ed37394SMagnus Damm 
454ed37394SMagnus Damm /*
464ed37394SMagnus Damm  * Default rate for the root input clock, reset this with clk_set_rate()
474ed37394SMagnus Damm  * from the platform code.
484ed37394SMagnus Damm  */
494ed37394SMagnus Damm struct clk extal_clk = {
504ed37394SMagnus Damm 	.name		= "extal",
514ed37394SMagnus Damm 	.id		= -1,
524ed37394SMagnus Damm 	.rate		= 33333333,
534ed37394SMagnus Damm };
544ed37394SMagnus Damm 
554ed37394SMagnus Damm /* The dll block multiplies the 32khz r_clk, may be used instead of extal */
564ed37394SMagnus Damm static unsigned long dll_recalc(struct clk *clk)
574ed37394SMagnus Damm {
584ed37394SMagnus Damm 	unsigned long mult;
594ed37394SMagnus Damm 
604ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
614ed37394SMagnus Damm 		mult = __raw_readl(DLLFRQ);
624ed37394SMagnus Damm 	else
634ed37394SMagnus Damm 		mult = 0;
644ed37394SMagnus Damm 
654ed37394SMagnus Damm 	return clk->parent->rate * mult;
664ed37394SMagnus Damm }
674ed37394SMagnus Damm 
684ed37394SMagnus Damm static struct clk_ops dll_clk_ops = {
694ed37394SMagnus Damm 	.recalc		= dll_recalc,
704ed37394SMagnus Damm };
714ed37394SMagnus Damm 
724ed37394SMagnus Damm static struct clk dll_clk = {
734ed37394SMagnus Damm 	.name           = "dll_clk",
744ed37394SMagnus Damm 	.id             = -1,
754ed37394SMagnus Damm 	.ops		= &dll_clk_ops,
764ed37394SMagnus Damm 	.parent		= &r_clk,
774ed37394SMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
784ed37394SMagnus Damm };
794ed37394SMagnus Damm 
804ed37394SMagnus Damm static unsigned long pll_recalc(struct clk *clk)
814ed37394SMagnus Damm {
824ed37394SMagnus Damm 	unsigned long mult = 1;
834ed37394SMagnus Damm 	unsigned long div = 1;
844ed37394SMagnus Damm 
854ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x4000)
864ed37394SMagnus Damm 		mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
874ed37394SMagnus Damm 	else
884ed37394SMagnus Damm 		div = 2;
894ed37394SMagnus Damm 
904ed37394SMagnus Damm 	return (clk->parent->rate * mult) / div;
914ed37394SMagnus Damm }
924ed37394SMagnus Damm 
934ed37394SMagnus Damm static struct clk_ops pll_clk_ops = {
944ed37394SMagnus Damm 	.recalc		= pll_recalc,
954ed37394SMagnus Damm };
964ed37394SMagnus Damm 
974ed37394SMagnus Damm static struct clk pll_clk = {
984ed37394SMagnus Damm 	.name		= "pll_clk",
994ed37394SMagnus Damm 	.id		= -1,
1004ed37394SMagnus Damm 	.ops		= &pll_clk_ops,
1014ed37394SMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
1024ed37394SMagnus Damm };
1034ed37394SMagnus Damm 
1044ed37394SMagnus Damm struct clk *main_clks[] = {
1054ed37394SMagnus Damm 	&r_clk,
1064ed37394SMagnus Damm 	&extal_clk,
1074ed37394SMagnus Damm 	&dll_clk,
1084ed37394SMagnus Damm 	&pll_clk,
1094ed37394SMagnus Damm };
1104ed37394SMagnus Damm 
1114ed37394SMagnus Damm static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
1124ed37394SMagnus Damm static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
1134ed37394SMagnus Damm 
1140a5f337eSMagnus Damm static struct clk_div_mult_table div4_div_mult_table = {
1154ed37394SMagnus Damm 	.divisors = divisors,
1164ed37394SMagnus Damm 	.nr_divisors = ARRAY_SIZE(divisors),
1174ed37394SMagnus Damm 	.multipliers = multipliers,
1184ed37394SMagnus Damm 	.nr_multipliers = ARRAY_SIZE(multipliers),
1194ed37394SMagnus Damm };
1204ed37394SMagnus Damm 
1210a5f337eSMagnus Damm static struct clk_div4_table div4_table = {
1220a5f337eSMagnus Damm 	.div_mult_table = &div4_div_mult_table,
1230a5f337eSMagnus Damm };
1240a5f337eSMagnus Damm 
1254ed37394SMagnus Damm enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
1264ed37394SMagnus Damm        DIV4_SIUA, DIV4_SIUB, DIV4_NR };
1274ed37394SMagnus Damm 
1284ed37394SMagnus Damm #define DIV4(_str, _reg, _bit, _mask, _flags) \
1294ed37394SMagnus Damm   SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
1304ed37394SMagnus Damm 
1314ed37394SMagnus Damm struct clk div4_clks[DIV4_NR] = {
1324ed37394SMagnus Damm 	[DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
1334ed37394SMagnus Damm 	[DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
1344ed37394SMagnus Damm 	[DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
1354ed37394SMagnus Damm 	[DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
1364ed37394SMagnus Damm 	[DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
1374ed37394SMagnus Damm 	[DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
1384ed37394SMagnus Damm 	[DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
1394ed37394SMagnus Damm 	[DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
1404ed37394SMagnus Damm };
1414ed37394SMagnus Damm 
142098ec49bSMagnus Damm enum { DIV6_V, DIV6_NR };
143098ec49bSMagnus Damm 
144098ec49bSMagnus Damm struct clk div6_clks[DIV6_NR] = {
1459e1985e1SMagnus Damm 	[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
1464ed37394SMagnus Damm };
1474ed37394SMagnus Damm 
1484ed37394SMagnus Damm #define MSTP(_str, _parent, _reg, _bit, _flags) \
1494ed37394SMagnus Damm   SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
1504ed37394SMagnus Damm 
1514780683aSMagnus Damm enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
1524780683aSMagnus Damm        MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
1534780683aSMagnus Damm        MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
1544780683aSMagnus Damm        MSTP007, MSTP006, MSTP005, MSTP002, MSTP001,
1554780683aSMagnus Damm        MSTP109, MSTP100,
1564780683aSMagnus Damm        MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217,
1574780683aSMagnus Damm        MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
1584780683aSMagnus Damm        MSTP_NR };
1594780683aSMagnus Damm 
1604780683aSMagnus Damm static struct clk mstp_clks[MSTP_NR] = {
1614ed37394SMagnus Damm 	/* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
1624780683aSMagnus Damm 	[MSTP031] = MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
1634780683aSMagnus Damm 	[MSTP030] = MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
1644780683aSMagnus Damm 	[MSTP029] = MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
1654780683aSMagnus Damm 	[MSTP028] = MSTP("rsmem0", &div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
1664780683aSMagnus Damm 	[MSTP026] = MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
1674780683aSMagnus Damm 	[MSTP023] = MSTP("intc3", &div4_clks[DIV4_P], MSTPCR0, 23, 0),
1684780683aSMagnus Damm 	[MSTP022] = MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 0),
1694780683aSMagnus Damm 	[MSTP021] = MSTP("dmac0", &div4_clks[DIV4_P], MSTPCR0, 21, 0),
1704780683aSMagnus Damm 	[MSTP020] = MSTP("sh0", &div4_clks[DIV4_P], MSTPCR0, 20, 0),
1714780683aSMagnus Damm 	[MSTP019] = MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0),
1724780683aSMagnus Damm 	[MSTP017] = MSTP("ubc0", &div4_clks[DIV4_P], MSTPCR0, 17, 0),
1734780683aSMagnus Damm 	[MSTP015] = MSTP("tmu_fck", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
1744780683aSMagnus Damm 	[MSTP014] = MSTP("cmt_fck", &r_clk, MSTPCR0, 14, 0),
1754780683aSMagnus Damm 	[MSTP013] = MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
1764780683aSMagnus Damm 	[MSTP011] = MSTP("mfi0", &div4_clks[DIV4_P], MSTPCR0, 11, 0),
1774780683aSMagnus Damm 	[MSTP010] = MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
1784780683aSMagnus Damm 	[MSTP007] = SH_CLK_MSTP32("sci_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 7, 0),
1794780683aSMagnus Damm 	[MSTP006] = SH_CLK_MSTP32("sci_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 6, 0),
1804780683aSMagnus Damm 	[MSTP005] = SH_CLK_MSTP32("sci_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 5, 0),
1814780683aSMagnus Damm 	[MSTP002] = MSTP("msiof0", &div4_clks[DIV4_P], MSTPCR0, 2, 0),
1824780683aSMagnus Damm 	[MSTP001] = MSTP("sbr0", &div4_clks[DIV4_P], MSTPCR0, 1, 0),
1834ed37394SMagnus Damm 
1844780683aSMagnus Damm 	[MSTP109] = MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
1854ed37394SMagnus Damm 
1864780683aSMagnus Damm 	[MSTP227] = MSTP("icb0", &div4_clks[DIV4_P], MSTPCR2, 27, 0),
1874780683aSMagnus Damm 	[MSTP226] = MSTP("meram0", &div4_clks[DIV4_P], MSTPCR2, 26, 0),
1884780683aSMagnus Damm 	[MSTP224] = MSTP("dacy1", &div4_clks[DIV4_P], MSTPCR2, 24, 0),
1894780683aSMagnus Damm 	[MSTP223] = MSTP("dacy0", &div4_clks[DIV4_P], MSTPCR2, 23, 0),
1904780683aSMagnus Damm 	[MSTP222] = MSTP("tsif0", &div4_clks[DIV4_P], MSTPCR2, 22, 0),
1914780683aSMagnus Damm 	[MSTP218] = MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
1924780683aSMagnus Damm 	[MSTP217] = MSTP("mmcif0", &div4_clks[DIV4_P], MSTPCR2, 17, 0),
1934780683aSMagnus Damm 	[MSTP211] = MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
1944780683aSMagnus Damm 	[MSTP207] = MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
1954780683aSMagnus Damm 	[MSTP205] = MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
1964780683aSMagnus Damm 	[MSTP204] = MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
1974780683aSMagnus Damm 	[MSTP203] = MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
1984780683aSMagnus Damm 	[MSTP202] = MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
1994780683aSMagnus Damm 	[MSTP201] = MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
2004780683aSMagnus Damm 	[MSTP200] = MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
2014ed37394SMagnus Damm };
2024ed37394SMagnus Damm 
203098ec49bSMagnus Damm #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
204098ec49bSMagnus Damm 
205098ec49bSMagnus Damm static struct clk_lookup lookups[] = {
206098ec49bSMagnus Damm 	/* DIV6 clocks */
207098ec49bSMagnus Damm 	CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
208098ec49bSMagnus Damm };
209098ec49bSMagnus Damm 
2104ed37394SMagnus Damm int __init arch_clk_init(void)
2114ed37394SMagnus Damm {
2124ed37394SMagnus Damm 	int k, ret = 0;
2134ed37394SMagnus Damm 
2144ed37394SMagnus Damm 	/* autodetect extal or dll configuration */
2154ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
2164ed37394SMagnus Damm 		pll_clk.parent = &dll_clk;
2174ed37394SMagnus Damm 	else
2184ed37394SMagnus Damm 		pll_clk.parent = &extal_clk;
2194ed37394SMagnus Damm 
2204ed37394SMagnus Damm 	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
2214ed37394SMagnus Damm 		ret = clk_register(main_clks[k]);
2224ed37394SMagnus Damm 
223098ec49bSMagnus Damm 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
224098ec49bSMagnus Damm 
2254ed37394SMagnus Damm 	if (!ret)
2264ed37394SMagnus Damm 		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
2274ed37394SMagnus Damm 
2284ed37394SMagnus Damm 	if (!ret)
229098ec49bSMagnus Damm 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
2304ed37394SMagnus Damm 
2314ed37394SMagnus Damm 	if (!ret)
2324780683aSMagnus Damm 		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
2334ed37394SMagnus Damm 
2344ed37394SMagnus Damm 	return ret;
2354ed37394SMagnus Damm }
236