aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Barinov <vbarinov@ru.mvista.com>2007-06-05 11:36:55 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-07-12 04:57:09 -0400
commit3e062b07ada88edb9ffdd147e39c7df4b4418f64 (patch)
tree0ebde9e0e6b3de7dd6ada32233d3db3106366e5f
parent7dcca30a32aadb0520417521b0c44f42d09fe05c (diff)
[ARM] 4430/1: davinci: clock control support
Support clock control driver for TI DaVinci SoC Signed-off-by: Vladimir Barinov <vbarinov@ru.mvista.com> Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-davinci/Makefile2
-rw-r--r--arch/arm/mach-davinci/board-evm.c2
-rw-r--r--arch/arm/mach-davinci/clock.c323
-rw-r--r--arch/arm/mach-davinci/clock.h33
-rw-r--r--arch/arm/mach-davinci/io.c6
-rw-r--r--include/asm-arm/arch-davinci/clock.h22
6 files changed, 387 insertions, 1 deletions
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index a8f88cd29905..b86c7f046204 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -4,7 +4,7 @@
4# 4#
5 5
6# Common objects 6# Common objects
7obj-y := time.o irq.o serial.o io.o id.o psc.o 7obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o
8 8
9# Board specific 9# Board specific
10obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o 10obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c
index 633c12e43044..9e4024c4965f 100644
--- a/arch/arm/mach-davinci/board-evm.c
+++ b/arch/arm/mach-davinci/board-evm.c
@@ -32,6 +32,7 @@
32void __init davinci_psc_init(void); 32void __init davinci_psc_init(void);
33void __init davinci_irq_init(void); 33void __init davinci_irq_init(void);
34void __init davinci_map_common_io(void); 34void __init davinci_map_common_io(void);
35void __init davinci_init_common_hw(void);
35 36
36/* NOR Flash base address set to CS0 by default */ 37/* NOR Flash base address set to CS0 by default */
37#define NOR_FLASH_PHYS 0x02000000 38#define NOR_FLASH_PHYS 0x02000000
@@ -116,6 +117,7 @@ static __init void davinci_evm_init(void)
116 117
117static __init void davinci_evm_irq_init(void) 118static __init void davinci_evm_irq_init(void)
118{ 119{
120 davinci_init_common_hw();
119 davinci_irq_init(); 121 davinci_irq_init();
120} 122}
121 123
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
new file mode 100644
index 000000000000..139ceaa35e24
--- /dev/null
+++ b/arch/arm/mach-davinci/clock.c
@@ -0,0 +1,323 @@
1/*
2 * TI DaVinci clock config file
3 *
4 * Copyright (C) 2006 Texas Instruments.
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; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/mutex.h>
18#include <linux/platform_device.h>
19
20#include <asm/hardware.h>
21#include <asm/io.h>
22
23#include <asm/arch/psc.h>
24#include "clock.h"
25
26/* PLL/Reset register offsets */
27#define PLLM 0x110
28
29static LIST_HEAD(clocks);
30static DEFINE_MUTEX(clocks_mutex);
31static DEFINE_SPINLOCK(clockfw_lock);
32
33static unsigned int commonrate;
34static unsigned int armrate;
35static unsigned int fixedrate = 27000000; /* 27 MHZ */
36
37extern void davinci_psc_config(unsigned int domain, unsigned int id, char enable);
38
39/*
40 * Returns a clock. Note that we first try to use device id on the bus
41 * and clock name. If this fails, we try to use clock name only.
42 */
43struct clk *clk_get(struct device *dev, const char *id)
44{
45 struct clk *p, *clk = ERR_PTR(-ENOENT);
46 int idno;
47
48 if (dev == NULL || dev->bus != &platform_bus_type)
49 idno = -1;
50 else
51 idno = to_platform_device(dev)->id;
52
53 mutex_lock(&clocks_mutex);
54
55 list_for_each_entry(p, &clocks, node) {
56 if (p->id == idno &&
57 strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
58 clk = p;
59 goto found;
60 }
61 }
62
63 list_for_each_entry(p, &clocks, node) {
64 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
65 clk = p;
66 break;
67 }
68 }
69
70found:
71 mutex_unlock(&clocks_mutex);
72
73 return clk;
74}
75EXPORT_SYMBOL(clk_get);
76
77void clk_put(struct clk *clk)
78{
79 if (clk && !IS_ERR(clk))
80 module_put(clk->owner);
81}
82EXPORT_SYMBOL(clk_put);
83
84static int __clk_enable(struct clk *clk)
85{
86 if (clk->flags & ALWAYS_ENABLED)
87 return 0;
88
89 davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 1);
90 return 0;
91}
92
93static void __clk_disable(struct clk *clk)
94{
95 if (clk->usecount)
96 return;
97
98 davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 0);
99}
100
101int clk_enable(struct clk *clk)
102{
103 unsigned long flags;
104 int ret = 0;
105
106 if (clk == NULL || IS_ERR(clk))
107 return -EINVAL;
108
109 if (clk->usecount++ == 0) {
110 spin_lock_irqsave(&clockfw_lock, flags);
111 ret = __clk_enable(clk);
112 spin_unlock_irqrestore(&clockfw_lock, flags);
113 }
114
115 return ret;
116}
117EXPORT_SYMBOL(clk_enable);
118
119void clk_disable(struct clk *clk)
120{
121 unsigned long flags;
122
123 if (clk == NULL || IS_ERR(clk))
124 return;
125
126 if (clk->usecount > 0 && !(--clk->usecount)) {
127 spin_lock_irqsave(&clockfw_lock, flags);
128 __clk_disable(clk);
129 spin_unlock_irqrestore(&clockfw_lock, flags);
130 }
131}
132EXPORT_SYMBOL(clk_disable);
133
134unsigned long clk_get_rate(struct clk *clk)
135{
136 if (clk == NULL || IS_ERR(clk))
137 return -EINVAL;
138
139 return *(clk->rate);
140}
141EXPORT_SYMBOL(clk_get_rate);
142
143long clk_round_rate(struct clk *clk, unsigned long rate)
144{
145 if (clk == NULL || IS_ERR(clk))
146 return -EINVAL;
147
148 return *(clk->rate);
149}
150EXPORT_SYMBOL(clk_round_rate);
151
152int clk_set_rate(struct clk *clk, unsigned long rate)
153{
154 if (clk == NULL || IS_ERR(clk))
155 return -EINVAL;
156
157 /* changing the clk rate is not supported */
158 return -EINVAL;
159}
160EXPORT_SYMBOL(clk_set_rate);
161
162int clk_register(struct clk *clk)
163{
164 if (clk == NULL || IS_ERR(clk))
165 return -EINVAL;
166
167 mutex_lock(&clocks_mutex);
168 list_add(&clk->node, &clocks);
169 mutex_unlock(&clocks_mutex);
170
171 return 0;
172}
173EXPORT_SYMBOL(clk_register);
174
175void clk_unregister(struct clk *clk)
176{
177 if (clk == NULL || IS_ERR(clk))
178 return;
179
180 mutex_lock(&clocks_mutex);
181 list_del(&clk->node);
182 mutex_unlock(&clocks_mutex);
183}
184EXPORT_SYMBOL(clk_unregister);
185
186static struct clk davinci_clks[] = {
187 {
188 .name = "ARMCLK",
189 .rate = &armrate,
190 .lpsc = -1,
191 .flags = ALWAYS_ENABLED,
192 },
193 {
194 .name = "UART",
195 .rate = &fixedrate,
196 .lpsc = DAVINCI_LPSC_UART0,
197 },
198 {
199 .name = "EMACCLK",
200 .rate = &commonrate,
201 .lpsc = DAVINCI_LPSC_EMAC_WRAPPER,
202 },
203 {
204 .name = "I2CCLK",
205 .rate = &fixedrate,
206 .lpsc = DAVINCI_LPSC_I2C,
207 },
208 {
209 .name = "IDECLK",
210 .rate = &commonrate,
211 .lpsc = DAVINCI_LPSC_ATA,
212 },
213 {
214 .name = "McBSPCLK",
215 .rate = &commonrate,
216 .lpsc = DAVINCI_LPSC_McBSP,
217 },
218 {
219 .name = "MMCSDCLK",
220 .rate = &commonrate,
221 .lpsc = DAVINCI_LPSC_MMC_SD,
222 },
223 {
224 .name = "SPICLK",
225 .rate = &commonrate,
226 .lpsc = DAVINCI_LPSC_SPI,
227 },
228 {
229 .name = "gpio",
230 .rate = &commonrate,
231 .lpsc = DAVINCI_LPSC_GPIO,
232 },
233 {
234 .name = "AEMIFCLK",
235 .rate = &commonrate,
236 .lpsc = DAVINCI_LPSC_AEMIF,
237 .usecount = 1,
238 }
239};
240
241int __init davinci_clk_init(void)
242{
243 struct clk *clkp;
244 int count = 0;
245 u32 pll_mult;
246
247 pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM);
248 commonrate = ((pll_mult + 1) * 27000000) / 6;
249 armrate = ((pll_mult + 1) * 27000000) / 2;
250
251 for (clkp = davinci_clks; count < ARRAY_SIZE(davinci_clks);
252 count++, clkp++) {
253 clk_register(clkp);
254
255 /* Turn on clocks that have been enabled in the
256 * table above */
257 if (clkp->usecount)
258 clk_enable(clkp);
259 }
260
261 return 0;
262}
263
264#ifdef CONFIG_PROC_FS
265#include <linux/proc_fs.h>
266#include <linux/seq_file.h>
267
268static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
269{
270 return *pos < 1 ? (void *)1 : NULL;
271}
272
273static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
274{
275 ++*pos;
276 return NULL;
277}
278
279static void davinci_ck_stop(struct seq_file *m, void *v)
280{
281}
282
283static int davinci_ck_show(struct seq_file *m, void *v)
284{
285 struct clk *cp;
286
287 list_for_each_entry(cp, &clocks, node)
288 seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount);
289
290 return 0;
291}
292
293static struct seq_operations davinci_ck_op = {
294 .start = davinci_ck_start,
295 .next = davinci_ck_next,
296 .stop = davinci_ck_stop,
297 .show = davinci_ck_show
298};
299
300static int davinci_ck_open(struct inode *inode, struct file *file)
301{
302 return seq_open(file, &davinci_ck_op);
303}
304
305static struct file_operations proc_davinci_ck_operations = {
306 .open = davinci_ck_open,
307 .read = seq_read,
308 .llseek = seq_lseek,
309 .release = seq_release,
310};
311
312static int __init davinci_ck_proc_init(void)
313{
314 struct proc_dir_entry *entry;
315
316 entry = create_proc_entry("davinci_clocks", 0, NULL);
317 if (entry)
318 entry->proc_fops = &proc_davinci_ck_operations;
319 return 0;
320
321}
322__initcall(davinci_ck_proc_init);
323#endif /* CONFIG_DEBUG_PROC_FS */
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
new file mode 100644
index 000000000000..ed47079a52e4
--- /dev/null
+++ b/arch/arm/mach-davinci/clock.h
@@ -0,0 +1,33 @@
1/*
2 * TI DaVinci clock definitions
3 *
4 * Copyright (C) 2006 Texas Instruments.
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef __ARCH_ARM_DAVINCI_CLOCK_H
12#define __ARCH_ARM_DAVINCI_CLOCK_H
13
14struct clk {
15 struct list_head node;
16 struct module *owner;
17 const char *name;
18 unsigned int *rate;
19 int id;
20 __s8 usecount;
21 __u8 flags;
22 __u8 lpsc;
23};
24
25/* Clock flags */
26#define RATE_CKCTL 1
27#define RATE_FIXED 2
28#define RATE_PROPAGATES 4
29#define VIRTUAL_CLOCK 8
30#define ALWAYS_ENABLED 16
31#define ENABLE_REG_32BIT 32
32
33#endif
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c
index 87fae6fb6ecf..47787ff84a6a 100644
--- a/arch/arm/mach-davinci/io.c
+++ b/arch/arm/mach-davinci/io.c
@@ -17,6 +17,7 @@
17#include <asm/memory.h> 17#include <asm/memory.h>
18 18
19#include <asm/mach/map.h> 19#include <asm/mach/map.h>
20#include <asm/arch/clock.h>
20 21
21extern void davinci_check_revision(void); 22extern void davinci_check_revision(void);
22 23
@@ -49,3 +50,8 @@ void __init davinci_map_common_io(void)
49 */ 50 */
50 davinci_check_revision(); 51 davinci_check_revision();
51} 52}
53
54void __init davinci_init_common_hw(void)
55{
56 davinci_clk_init();
57}
diff --git a/include/asm-arm/arch-davinci/clock.h b/include/asm-arm/arch-davinci/clock.h
new file mode 100644
index 000000000000..cc168b7a14f2
--- /dev/null
+++ b/include/asm-arm/arch-davinci/clock.h
@@ -0,0 +1,22 @@
1/*
2 * include/asm-arm/arch-davinci/clock.h
3 *
4 * Clock control driver for DaVinci - header file
5 *
6 * Authors: Vladimir Barinov <source@mvista.com>
7 *
8 * 2007 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13#ifndef __ASM_ARCH_DAVINCI_CLOCK_H
14#define __ASM_ARCH_DAVINCI_CLOCK_H
15
16struct clk;
17
18extern int clk_register(struct clk *clk);
19extern void clk_unregister(struct clk *clk);
20extern int davinci_clk_init(void);
21
22#endif