| Pawel Moll | bcd6f56 | 2012-09-18 15:17:48 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * This program is free software; you can redistribute it and/or modify | 
 | 3 |  * it under the terms of the GNU General Public License version 2 as | 
 | 4 |  * published by the Free Software Foundation. | 
 | 5 |  * | 
 | 6 |  * This program is distributed in the hope that it will be useful, | 
 | 7 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 8 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 9 |  * GNU General Public License for more details. | 
 | 10 |  * | 
 | 11 |  * Copyright (C) 2012 ARM Limited | 
 | 12 |  */ | 
 | 13 |  | 
| Catalin Marinas | da660b4 | 2013-01-04 14:17:15 +0000 | [diff] [blame] | 14 | #include <linux/amba/sp810.h> | 
| Pawel Moll | bcd6f56 | 2012-09-18 15:17:48 +0100 | [diff] [blame] | 15 | #include <linux/clkdev.h> | 
 | 16 | #include <linux/clk-provider.h> | 
 | 17 | #include <linux/err.h> | 
| Pawel Moll | bcd6f56 | 2012-09-18 15:17:48 +0100 | [diff] [blame] | 18 | #include <linux/vexpress.h> | 
 | 19 |  | 
| Pawel Moll | bcd6f56 | 2012-09-18 15:17:48 +0100 | [diff] [blame] | 20 | static struct clk *vexpress_sp810_timerclken[4]; | 
 | 21 | static DEFINE_SPINLOCK(vexpress_sp810_lock); | 
 | 22 |  | 
 | 23 | static void __init vexpress_sp810_init(void __iomem *base) | 
 | 24 | { | 
 | 25 | 	int i; | 
 | 26 |  | 
 | 27 | 	if (WARN_ON(!base)) | 
 | 28 | 		return; | 
 | 29 |  | 
 | 30 | 	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) { | 
 | 31 | 		char name[12]; | 
 | 32 | 		const char *parents[] = { | 
 | 33 | 			"v2m:refclk32khz", /* REFCLK */ | 
 | 34 | 			"v2m:refclk1mhz" /* TIMCLK */ | 
 | 35 | 		}; | 
 | 36 |  | 
 | 37 | 		snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); | 
 | 38 |  | 
 | 39 | 		vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name, | 
 | 40 | 				parents, 2, 0, base + SCCTRL, | 
 | 41 | 				SCCTRL_TIMERENnSEL_SHIFT(i), 1, | 
 | 42 | 				0, &vexpress_sp810_lock); | 
 | 43 |  | 
 | 44 | 		if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i]))) | 
 | 45 | 			break; | 
 | 46 | 	} | 
 | 47 | } | 
 | 48 |  | 
 | 49 |  | 
 | 50 | static const char * const vexpress_clk_24mhz_periphs[] __initconst = { | 
 | 51 | 	"mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3", | 
 | 52 | 	"mb:mmci", "mb:kmi0", "mb:kmi1" | 
 | 53 | }; | 
 | 54 |  | 
 | 55 | void __init vexpress_clk_init(void __iomem *sp810_base) | 
 | 56 | { | 
 | 57 | 	struct clk *clk; | 
 | 58 | 	int i; | 
 | 59 |  | 
 | 60 | 	clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL, | 
 | 61 | 			CLK_IS_ROOT, 0); | 
 | 62 | 	WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL)); | 
 | 63 |  | 
 | 64 | 	clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL, | 
 | 65 | 			CLK_IS_ROOT, 24000000); | 
 | 66 | 	for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++) | 
 | 67 | 		WARN_ON(clk_register_clkdev(clk, NULL, | 
 | 68 | 				vexpress_clk_24mhz_periphs[i])); | 
 | 69 |  | 
 | 70 | 	clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL, | 
 | 71 | 			CLK_IS_ROOT, 32768); | 
 | 72 | 	WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt")); | 
 | 73 |  | 
 | 74 | 	clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL, | 
 | 75 | 			CLK_IS_ROOT, 1000000); | 
 | 76 |  | 
 | 77 | 	vexpress_sp810_init(sp810_base); | 
 | 78 |  | 
 | 79 | 	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) | 
 | 80 | 		WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk)); | 
 | 81 |  | 
 | 82 | 	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0], | 
 | 83 | 				"v2m-timer0", "sp804")); | 
 | 84 | 	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1], | 
 | 85 | 				"v2m-timer1", "sp804")); | 
 | 86 | } |