Commit | Line | Data |
---|---|---|
171bb2f1 JC |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify it | |
3 | * under the terms of the GNU General Public License version 2 as published | |
4 | * by the Free Software Foundation. | |
5 | * | |
6 | * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> | |
7 | * Copyright (C) 2010 John Crispin <blogic@openwrt.org> | |
8 | */ | |
9 | #include <linux/io.h> | |
4af92e7a | 10 | #include <linux/export.h> |
171bb2f1 JC |
11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> | |
13 | #include <linux/types.h> | |
14 | #include <linux/clk.h> | |
287e3f3f | 15 | #include <linux/clkdev.h> |
171bb2f1 JC |
16 | #include <linux/err.h> |
17 | #include <linux/list.h> | |
18 | ||
19 | #include <asm/time.h> | |
20 | #include <asm/irq.h> | |
21 | #include <asm/div64.h> | |
22 | ||
23 | #include <lantiq_soc.h> | |
24 | ||
25 | #include "clk.h" | |
287e3f3f | 26 | #include "prom.h" |
171bb2f1 | 27 | |
287e3f3f | 28 | /* lantiq socs have 3 static clocks */ |
740c606e | 29 | static struct clk cpu_clk_generic[4]; |
171bb2f1 | 30 | |
740c606e JC |
31 | void clkdev_add_static(unsigned long cpu, unsigned long fpi, |
32 | unsigned long io, unsigned long ppe) | |
287e3f3f JC |
33 | { |
34 | cpu_clk_generic[0].rate = cpu; | |
35 | cpu_clk_generic[1].rate = fpi; | |
36 | cpu_clk_generic[2].rate = io; | |
740c606e | 37 | cpu_clk_generic[3].rate = ppe; |
287e3f3f | 38 | } |
171bb2f1 | 39 | |
287e3f3f JC |
40 | struct clk *clk_get_cpu(void) |
41 | { | |
42 | return &cpu_clk_generic[0]; | |
43 | } | |
44 | ||
45 | struct clk *clk_get_fpi(void) | |
46 | { | |
47 | return &cpu_clk_generic[1]; | |
48 | } | |
49 | EXPORT_SYMBOL_GPL(clk_get_fpi); | |
50 | ||
51 | struct clk *clk_get_io(void) | |
171bb2f1 | 52 | { |
287e3f3f | 53 | return &cpu_clk_generic[2]; |
171bb2f1 JC |
54 | } |
55 | ||
740c606e JC |
56 | struct clk *clk_get_ppe(void) |
57 | { | |
58 | return &cpu_clk_generic[3]; | |
59 | } | |
60 | EXPORT_SYMBOL_GPL(clk_get_ppe); | |
61 | ||
171bb2f1 JC |
62 | static inline int clk_good(struct clk *clk) |
63 | { | |
64 | return clk && !IS_ERR(clk); | |
65 | } | |
66 | ||
67 | unsigned long clk_get_rate(struct clk *clk) | |
68 | { | |
69 | if (unlikely(!clk_good(clk))) | |
70 | return 0; | |
71 | ||
72 | if (clk->rate != 0) | |
73 | return clk->rate; | |
74 | ||
75 | if (clk->get_rate != NULL) | |
76 | return clk->get_rate(); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | EXPORT_SYMBOL(clk_get_rate); | |
81 | ||
287e3f3f | 82 | int clk_set_rate(struct clk *clk, unsigned long rate) |
171bb2f1 | 83 | { |
287e3f3f JC |
84 | if (unlikely(!clk_good(clk))) |
85 | return 0; | |
86 | if (clk->rates && *clk->rates) { | |
87 | unsigned long *r = clk->rates; | |
88 | ||
89 | while (*r && (*r != rate)) | |
90 | r++; | |
91 | if (!*r) { | |
92 | pr_err("clk %s.%s: trying to set invalid rate %ld\n", | |
93 | clk->cl.dev_id, clk->cl.con_id, rate); | |
94 | return -1; | |
95 | } | |
96 | } | |
97 | clk->rate = rate; | |
98 | return 0; | |
171bb2f1 | 99 | } |
287e3f3f | 100 | EXPORT_SYMBOL(clk_set_rate); |
171bb2f1 | 101 | |
744120aa JC |
102 | int clk_enable(struct clk *clk) |
103 | { | |
287e3f3f JC |
104 | if (unlikely(!clk_good(clk))) |
105 | return -1; | |
106 | ||
107 | if (clk->enable) | |
108 | return clk->enable(clk); | |
109 | ||
110 | return -1; | |
744120aa JC |
111 | } |
112 | EXPORT_SYMBOL(clk_enable); | |
113 | ||
114 | void clk_disable(struct clk *clk) | |
115 | { | |
287e3f3f JC |
116 | if (unlikely(!clk_good(clk))) |
117 | return; | |
118 | ||
119 | if (clk->disable) | |
120 | clk->disable(clk); | |
744120aa JC |
121 | } |
122 | EXPORT_SYMBOL(clk_disable); | |
123 | ||
287e3f3f JC |
124 | int clk_activate(struct clk *clk) |
125 | { | |
126 | if (unlikely(!clk_good(clk))) | |
127 | return -1; | |
128 | ||
129 | if (clk->activate) | |
130 | return clk->activate(clk); | |
131 | ||
132 | return -1; | |
133 | } | |
134 | EXPORT_SYMBOL(clk_activate); | |
135 | ||
136 | void clk_deactivate(struct clk *clk) | |
137 | { | |
138 | if (unlikely(!clk_good(clk))) | |
139 | return; | |
140 | ||
141 | if (clk->deactivate) | |
142 | clk->deactivate(clk); | |
143 | } | |
144 | EXPORT_SYMBOL(clk_deactivate); | |
145 | ||
b902d9a9 JC |
146 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) |
147 | { | |
148 | return NULL; | |
149 | } | |
150 | ||
287e3f3f | 151 | static inline u32 get_counter_resolution(void) |
171bb2f1 JC |
152 | { |
153 | u32 res; | |
154 | ||
155 | __asm__ __volatile__( | |
70342287 RB |
156 | ".set push\n" |
157 | ".set mips32r2\n" | |
158 | "rdhwr %0, $3\n" | |
171bb2f1 JC |
159 | ".set pop\n" |
160 | : "=&r" (res) | |
161 | : /* no input */ | |
162 | : "memory"); | |
163 | ||
164 | return res; | |
165 | } | |
166 | ||
167 | void __init plat_time_init(void) | |
168 | { | |
169 | struct clk *clk; | |
170 | ||
287e3f3f | 171 | ltq_soc_init(); |
171bb2f1 | 172 | |
287e3f3f JC |
173 | clk = clk_get_cpu(); |
174 | mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); | |
171bb2f1 | 175 | write_c0_compare(read_c0_count()); |
287e3f3f | 176 | pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); |
171bb2f1 JC |
177 | clk_put(clk); |
178 | } |