aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2012-09-18 10:17:48 -0400
committerMike Turquette <mturquette@linaro.org>2012-10-29 14:08:03 -0400
commitbcd6f569e87471d7f104bd9497f0b516a3b12e32 (patch)
treeb15f2f2b9a78232c1f70689d3d5ca35d1ed64168
parented27ff1db869cc81a92bed6defb7d107f5a156ff (diff)
clk: Common clocks implementation for Versatile Express
This patch adds a DT and non-DT based implementation of the common clock infrastructure for Versatile Express platform. It registers (statically or using DT) all required fixed clocks, initialises motherboard's SP810 cell (that provides clocks for SP804 timers) and explicitly registers VE "osc" driver, to make the clock generators available early. Signed-off-by: Pawel Moll <pawel.moll@arm.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--arch/arm/include/asm/hardware/sp810.h2
-rw-r--r--drivers/clk/Kconfig8
-rw-r--r--drivers/clk/versatile/Makefile1
-rw-r--r--drivers/clk/versatile/clk-vexpress.c142
4 files changed, 150 insertions, 3 deletions
diff --git a/arch/arm/include/asm/hardware/sp810.h b/arch/arm/include/asm/hardware/sp810.h
index 6b9b077d86b..afd7e916472 100644
--- a/arch/arm/include/asm/hardware/sp810.h
+++ b/arch/arm/include/asm/hardware/sp810.h
@@ -56,6 +56,8 @@
56#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17) 56#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17)
57#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17) 57#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17)
58 58
59#define SCCTRL_TIMERENnSEL_SHIFT(n) (15 + ((n) * 2))
60
59static inline void sysctl_soft_reset(void __iomem *base) 61static inline void sysctl_soft_reset(void __iomem *base)
60{ 62{
61 /* switch to slow mode */ 63 /* switch to slow mode */
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3d0b7843852..823f62d900b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X
42 42
43config COMMON_CLK_VERSATILE 43config COMMON_CLK_VERSATILE
44 bool "Clock driver for ARM Reference designs" 44 bool "Clock driver for ARM Reference designs"
45 depends on ARCH_INTEGRATOR || ARCH_REALVIEW 45 depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
46 ---help--- 46 ---help---
47 Supports clocking on ARM Reference designs Integrator/AP, 47 Supports clocking on ARM Reference designs:
48 Integrator/CP, RealView PB1176, EB, PB11MP and PBX. 48 - Integrator/AP and Integrator/CP
49 - RealView PB1176, EB, PB11MP and PBX
50 - Versatile Express
49 51
50config COMMON_CLK_MAX77686 52config COMMON_CLK_MAX77686
51 tristate "Clock driver for Maxim 77686 MFD" 53 tristate "Clock driver for Maxim 77686 MFD"
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index 1e49a7afcf4..c776053e5bb 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -2,4 +2,5 @@
2obj-$(CONFIG_ICST) += clk-icst.o 2obj-$(CONFIG_ICST) += clk-icst.o
3obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o 3obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
4obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o 4obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
5obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
5obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o 6obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
new file mode 100644
index 00000000000..c742ac7c60b
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -0,0 +1,142 @@
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
14#include <linux/clkdev.h>
15#include <linux/clk-provider.h>
16#include <linux/err.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19#include <linux/vexpress.h>
20
21#include <asm/hardware/sp810.h>
22
23static struct clk *vexpress_sp810_timerclken[4];
24static DEFINE_SPINLOCK(vexpress_sp810_lock);
25
26static void __init vexpress_sp810_init(void __iomem *base)
27{
28 int i;
29
30 if (WARN_ON(!base))
31 return;
32
33 for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
34 char name[12];
35 const char *parents[] = {
36 "v2m:refclk32khz", /* REFCLK */
37 "v2m:refclk1mhz" /* TIMCLK */
38 };
39
40 snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
41
42 vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
43 parents, 2, 0, base + SCCTRL,
44 SCCTRL_TIMERENnSEL_SHIFT(i), 1,
45 0, &vexpress_sp810_lock);
46
47 if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
48 break;
49 }
50}
51
52
53static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
54 "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
55 "mb:mmci", "mb:kmi0", "mb:kmi1"
56};
57
58void __init vexpress_clk_init(void __iomem *sp810_base)
59{
60 struct clk *clk;
61 int i;
62
63 clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
64 CLK_IS_ROOT, 0);
65 WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
66
67 clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
68 CLK_IS_ROOT, 24000000);
69 for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
70 WARN_ON(clk_register_clkdev(clk, NULL,
71 vexpress_clk_24mhz_periphs[i]));
72
73 clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
74 CLK_IS_ROOT, 32768);
75 WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
76
77 clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
78 CLK_IS_ROOT, 1000000);
79
80 vexpress_sp810_init(sp810_base);
81
82 for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
83 WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk));
84
85 WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
86 "v2m-timer0", "sp804"));
87 WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
88 "v2m-timer1", "sp804"));
89}
90
91#if defined(CONFIG_OF)
92
93struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
94{
95 if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
96 ARRAY_SIZE(vexpress_sp810_timerclken)))
97 return NULL;
98
99 return vexpress_sp810_timerclken[clkspec->args[0]];
100}
101
102static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
103 { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
104 { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
105 {}
106};
107
108void __init vexpress_clk_of_init(void)
109{
110 struct device_node *node;
111 struct clk *clk;
112 struct clk *refclk, *timclk;
113
114 of_clk_init(vexpress_fixed_clk_match);
115
116 node = of_find_compatible_node(NULL, NULL, "arm,sp810");
117 vexpress_sp810_init(of_iomap(node, 0));
118 of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
119
120 /* Select "better" (faster) parent for SP804 timers */
121 refclk = of_clk_get_by_name(node, "refclk");
122 timclk = of_clk_get_by_name(node, "timclk");
123 if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
124 int i = 0;
125
126 if (clk_get_rate(refclk) > clk_get_rate(timclk))
127 clk = refclk;
128 else
129 clk = timclk;
130
131 for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
132 WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
133 clk));
134 }
135
136 WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
137 "v2m-timer0", "sp804"));
138 WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
139 "v2m-timer1", "sp804"));
140}
141
142#endif