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> | |
97b92108 | 7 | * Copyright (C) 2010 John Crispin <john@phrozen.org> |
171bb2f1 JC |
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 | |
500fab97 HM |
102 | long clk_round_rate(struct clk *clk, unsigned long rate) |
103 | { | |
104 | if (unlikely(!clk_good(clk))) | |
105 | return 0; | |
106 | if (clk->rates && *clk->rates) { | |
107 | unsigned long *r = clk->rates; | |
108 | ||
109 | while (*r && (*r != rate)) | |
110 | r++; | |
111 | if (!*r) { | |
112 | return clk->rate; | |
113 | } | |
114 | } | |
115 | return rate; | |
116 | } | |
117 | EXPORT_SYMBOL(clk_round_rate); | |
118 | ||
744120aa JC |
119 | int clk_enable(struct clk *clk) |
120 | { | |
287e3f3f JC |
121 | if (unlikely(!clk_good(clk))) |
122 | return -1; | |
123 | ||
124 | if (clk->enable) | |
125 | return clk->enable(clk); | |
126 | ||
127 | return -1; | |
744120aa JC |
128 | } |
129 | EXPORT_SYMBOL(clk_enable); | |
130 | ||
131 | void clk_disable(struct clk *clk) | |
132 | { | |
287e3f3f JC |
133 | if (unlikely(!clk_good(clk))) |
134 | return; | |
135 | ||
136 | if (clk->disable) | |
137 | clk->disable(clk); | |
744120aa JC |
138 | } |
139 | EXPORT_SYMBOL(clk_disable); | |
140 | ||
287e3f3f JC |
141 | int clk_activate(struct clk *clk) |
142 | { | |
143 | if (unlikely(!clk_good(clk))) | |
144 | return -1; | |
145 | ||
146 | if (clk->activate) | |
147 | return clk->activate(clk); | |
148 | ||
149 | return -1; | |
150 | } | |
151 | EXPORT_SYMBOL(clk_activate); | |
152 | ||
153 | void clk_deactivate(struct clk *clk) | |
154 | { | |
155 | if (unlikely(!clk_good(clk))) | |
156 | return; | |
157 | ||
158 | if (clk->deactivate) | |
159 | clk->deactivate(clk); | |
160 | } | |
161 | EXPORT_SYMBOL(clk_deactivate); | |
162 | ||
b902d9a9 JC |
163 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) |
164 | { | |
165 | return NULL; | |
166 | } | |
167 | ||
287e3f3f | 168 | static inline u32 get_counter_resolution(void) |
171bb2f1 JC |
169 | { |
170 | u32 res; | |
171 | ||
172 | __asm__ __volatile__( | |
70342287 RB |
173 | ".set push\n" |
174 | ".set mips32r2\n" | |
175 | "rdhwr %0, $3\n" | |
171bb2f1 JC |
176 | ".set pop\n" |
177 | : "=&r" (res) | |
178 | : /* no input */ | |
179 | : "memory"); | |
180 | ||
181 | return res; | |
182 | } | |
183 | ||
184 | void __init plat_time_init(void) | |
185 | { | |
186 | struct clk *clk; | |
187 | ||
287e3f3f | 188 | ltq_soc_init(); |
171bb2f1 | 189 | |
287e3f3f JC |
190 | clk = clk_get_cpu(); |
191 | mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); | |
171bb2f1 | 192 | write_c0_compare(read_c0_count()); |
287e3f3f | 193 | pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); |
171bb2f1 JC |
194 | clk_put(clk); |
195 | } |