diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 22:03:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 22:03:06 -0400 |
commit | 16d8775700f1815076f879719ce14b33f50a3171 (patch) | |
tree | 8525e6e6f12b6acf7cf2746853cc65549f3dbf4c /arch/arm/plat-spear | |
parent | e34551339a195aa548eaf698523714a8fe7f1984 (diff) | |
parent | 05e34754518b6a90d5c392790c032575fab12d66 (diff) |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (91 commits)
ARM: 6806/1: irq: introduce entry and exit functions for chained handlers
ARM: 6781/1: Thumb-2: Work around buggy Thumb-2 short branch relocations in gas
ARM: 6747/1: P2V: Thumb2 support
ARM: 6798/1: aout-core: zero thread debug registers in a.out core dump
ARM: 6796/1: Footbridge: Fix I/O mappings for NOMMU mode
ARM: 6784/1: errata: no automatic Store Buffer drain on Cortex-A9
ARM: 6772/1: errata: possible fault MMU translations following an ASID switch
ARM: 6776/1: mach-ux500: activate fix for errata 753970
ARM: 6794/1: SPEAr: Append UL to device address macros.
ARM: 6793/1: SPEAr: Remove unused *_SIZE macros from spear*.h files
ARM: 6792/1: SPEAr: Replace SIZE macro's with SZ_4K macros
ARM: 6791/1: SPEAr3xx: Declare device structures after shirq code
ARM: 6790/1: SPEAr: Clock Framework: Rename usbd clock and align apb_clk entry
ARM: 6789/1: SPEAr3xx: Rename sdio to sdhci
ARM: 6788/1: SPEAr: Include mach/hardware.h instead of mach/spear.h
ARM: 6787/1: SPEAr: Reorder #includes in .h & .c files.
ARM: 6681/1: SPEAr: add debugfs support to clk API
ARM: 6703/1: SPEAr: update clk API support
ARM: 6679/1: SPEAr: make clk API functions more generic
ARM: 6737/1: SPEAr: formalized timer support
...
Diffstat (limited to 'arch/arm/plat-spear')
-rw-r--r-- | arch/arm/plat-spear/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/plat-spear/clock.c | 844 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/clock.h | 166 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/debug-macro.S | 2 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/hardware.h | 23 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/memory.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/system.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/uncompress.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-spear/time.c | 26 |
9 files changed, 890 insertions, 183 deletions
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index eb89540aeda9..b4f340b8f1f1 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile | |||
@@ -3,6 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := clock.o padmux.o time.o | 6 | obj-y := clock.o time.o |
7 | 7 | ||
8 | obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o | 8 | obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o padmux.o |
diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c index ee4f90e534d8..bdbd7ec9cb6b 100644 --- a/arch/arm/plat-spear/clock.c +++ b/arch/arm/plat-spear/clock.c | |||
@@ -12,18 +12,25 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/clk.h> | ||
16 | #include <linux/debugfs.h> | ||
15 | #include <linux/err.h> | 17 | #include <linux/err.h> |
16 | #include <linux/io.h> | 18 | #include <linux/io.h> |
17 | #include <linux/list.h> | 19 | #include <linux/list.h> |
18 | #include <linux/module.h> | 20 | #include <linux/module.h> |
19 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
20 | #include <mach/misc_regs.h> | ||
21 | #include <plat/clock.h> | 22 | #include <plat/clock.h> |
22 | 23 | ||
23 | static DEFINE_SPINLOCK(clocks_lock); | 24 | static DEFINE_SPINLOCK(clocks_lock); |
24 | static LIST_HEAD(root_clks); | 25 | static LIST_HEAD(root_clks); |
26 | #ifdef CONFIG_DEBUG_FS | ||
27 | static LIST_HEAD(clocks); | ||
28 | #endif | ||
25 | 29 | ||
26 | static void propagate_rate(struct list_head *); | 30 | static void propagate_rate(struct clk *, int on_init); |
31 | #ifdef CONFIG_DEBUG_FS | ||
32 | static int clk_debugfs_reparent(struct clk *); | ||
33 | #endif | ||
27 | 34 | ||
28 | static int generic_clk_enable(struct clk *clk) | 35 | static int generic_clk_enable(struct clk *clk) |
29 | { | 36 | { |
@@ -65,6 +72,104 @@ static struct clkops generic_clkops = { | |||
65 | .disable = generic_clk_disable, | 72 | .disable = generic_clk_disable, |
66 | }; | 73 | }; |
67 | 74 | ||
75 | /* returns current programmed clocks clock info structure */ | ||
76 | static struct pclk_info *pclk_info_get(struct clk *clk) | ||
77 | { | ||
78 | unsigned int val, i; | ||
79 | struct pclk_info *info = NULL; | ||
80 | |||
81 | val = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) | ||
82 | & clk->pclk_sel->pclk_sel_mask; | ||
83 | |||
84 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | ||
85 | if (clk->pclk_sel->pclk_info[i].pclk_val == val) | ||
86 | info = &clk->pclk_sel->pclk_info[i]; | ||
87 | } | ||
88 | |||
89 | return info; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Set Update pclk, and pclk_info of clk and add clock sibling node to current | ||
94 | * parents children list | ||
95 | */ | ||
96 | static void clk_reparent(struct clk *clk, struct pclk_info *pclk_info) | ||
97 | { | ||
98 | unsigned long flags; | ||
99 | |||
100 | spin_lock_irqsave(&clocks_lock, flags); | ||
101 | list_del(&clk->sibling); | ||
102 | list_add(&clk->sibling, &pclk_info->pclk->children); | ||
103 | |||
104 | clk->pclk = pclk_info->pclk; | ||
105 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
106 | |||
107 | #ifdef CONFIG_DEBUG_FS | ||
108 | clk_debugfs_reparent(clk); | ||
109 | #endif | ||
110 | } | ||
111 | |||
112 | static void do_clk_disable(struct clk *clk) | ||
113 | { | ||
114 | if (!clk) | ||
115 | return; | ||
116 | |||
117 | if (!clk->usage_count) { | ||
118 | WARN_ON(1); | ||
119 | return; | ||
120 | } | ||
121 | |||
122 | clk->usage_count--; | ||
123 | |||
124 | if (clk->usage_count == 0) { | ||
125 | /* | ||
126 | * Surely, there are no active childrens or direct users | ||
127 | * of this clock | ||
128 | */ | ||
129 | if (clk->pclk) | ||
130 | do_clk_disable(clk->pclk); | ||
131 | |||
132 | if (clk->ops && clk->ops->disable) | ||
133 | clk->ops->disable(clk); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static int do_clk_enable(struct clk *clk) | ||
138 | { | ||
139 | int ret = 0; | ||
140 | |||
141 | if (!clk) | ||
142 | return -EFAULT; | ||
143 | |||
144 | if (clk->usage_count == 0) { | ||
145 | if (clk->pclk) { | ||
146 | ret = do_clk_enable(clk->pclk); | ||
147 | if (ret) | ||
148 | goto err; | ||
149 | } | ||
150 | if (clk->ops && clk->ops->enable) { | ||
151 | ret = clk->ops->enable(clk); | ||
152 | if (ret) { | ||
153 | if (clk->pclk) | ||
154 | do_clk_disable(clk->pclk); | ||
155 | goto err; | ||
156 | } | ||
157 | } | ||
158 | /* | ||
159 | * Since the clock is going to be used for the first | ||
160 | * time please reclac | ||
161 | */ | ||
162 | if (clk->recalc) { | ||
163 | ret = clk->recalc(clk); | ||
164 | if (ret) | ||
165 | goto err; | ||
166 | } | ||
167 | } | ||
168 | clk->usage_count++; | ||
169 | err: | ||
170 | return ret; | ||
171 | } | ||
172 | |||
68 | /* | 173 | /* |
69 | * clk_enable - inform the system when the clock source should be running. | 174 | * clk_enable - inform the system when the clock source should be running. |
70 | * @clk: clock source | 175 | * @clk: clock source |
@@ -78,17 +183,9 @@ int clk_enable(struct clk *clk) | |||
78 | unsigned long flags; | 183 | unsigned long flags; |
79 | int ret = 0; | 184 | int ret = 0; |
80 | 185 | ||
81 | if (!clk || IS_ERR(clk)) | ||
82 | return -EFAULT; | ||
83 | |||
84 | spin_lock_irqsave(&clocks_lock, flags); | 186 | spin_lock_irqsave(&clocks_lock, flags); |
85 | if (clk->usage_count == 0) { | 187 | ret = do_clk_enable(clk); |
86 | if (clk->ops && clk->ops->enable) | ||
87 | ret = clk->ops->enable(clk); | ||
88 | } | ||
89 | clk->usage_count++; | ||
90 | spin_unlock_irqrestore(&clocks_lock, flags); | 188 | spin_unlock_irqrestore(&clocks_lock, flags); |
91 | |||
92 | return ret; | 189 | return ret; |
93 | } | 190 | } |
94 | EXPORT_SYMBOL(clk_enable); | 191 | EXPORT_SYMBOL(clk_enable); |
@@ -109,17 +206,8 @@ void clk_disable(struct clk *clk) | |||
109 | { | 206 | { |
110 | unsigned long flags; | 207 | unsigned long flags; |
111 | 208 | ||
112 | if (!clk || IS_ERR(clk)) | ||
113 | return; | ||
114 | |||
115 | WARN_ON(clk->usage_count == 0); | ||
116 | |||
117 | spin_lock_irqsave(&clocks_lock, flags); | 209 | spin_lock_irqsave(&clocks_lock, flags); |
118 | clk->usage_count--; | 210 | do_clk_disable(clk); |
119 | if (clk->usage_count == 0) { | ||
120 | if (clk->ops && clk->ops->disable) | ||
121 | clk->ops->disable(clk); | ||
122 | } | ||
123 | spin_unlock_irqrestore(&clocks_lock, flags); | 211 | spin_unlock_irqrestore(&clocks_lock, flags); |
124 | } | 212 | } |
125 | EXPORT_SYMBOL(clk_disable); | 213 | EXPORT_SYMBOL(clk_disable); |
@@ -153,15 +241,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
153 | int i, found = 0, val = 0; | 241 | int i, found = 0, val = 0; |
154 | unsigned long flags; | 242 | unsigned long flags; |
155 | 243 | ||
156 | if (!clk || IS_ERR(clk) || !parent || IS_ERR(parent)) | 244 | if (!clk || !parent) |
157 | return -EFAULT; | 245 | return -EFAULT; |
158 | if (clk->usage_count) | ||
159 | return -EBUSY; | ||
160 | if (!clk->pclk_sel) | ||
161 | return -EPERM; | ||
162 | if (clk->pclk == parent) | 246 | if (clk->pclk == parent) |
163 | return 0; | 247 | return 0; |
248 | if (!clk->pclk_sel) | ||
249 | return -EPERM; | ||
164 | 250 | ||
251 | /* check if requested parent is in clk parent list */ | ||
165 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | 252 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { |
166 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { | 253 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { |
167 | found = 1; | 254 | found = 1; |
@@ -176,25 +263,58 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
176 | /* reflect parent change in hardware */ | 263 | /* reflect parent change in hardware */ |
177 | val = readl(clk->pclk_sel->pclk_sel_reg); | 264 | val = readl(clk->pclk_sel->pclk_sel_reg); |
178 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); | 265 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); |
179 | val |= clk->pclk_sel->pclk_info[i].pclk_mask << clk->pclk_sel_shift; | 266 | val |= clk->pclk_sel->pclk_info[i].pclk_val << clk->pclk_sel_shift; |
180 | writel(val, clk->pclk_sel->pclk_sel_reg); | 267 | writel(val, clk->pclk_sel->pclk_sel_reg); |
181 | spin_unlock_irqrestore(&clocks_lock, flags); | 268 | spin_unlock_irqrestore(&clocks_lock, flags); |
182 | 269 | ||
183 | /* reflect parent change in software */ | 270 | /* reflect parent change in software */ |
184 | clk->recalc(clk); | 271 | clk_reparent(clk, &clk->pclk_sel->pclk_info[i]); |
185 | propagate_rate(&clk->children); | 272 | |
273 | propagate_rate(clk, 0); | ||
186 | return 0; | 274 | return 0; |
187 | } | 275 | } |
188 | EXPORT_SYMBOL(clk_set_parent); | 276 | EXPORT_SYMBOL(clk_set_parent); |
189 | 277 | ||
278 | /** | ||
279 | * clk_set_rate - set the clock rate for a clock source | ||
280 | * @clk: clock source | ||
281 | * @rate: desired clock rate in Hz | ||
282 | * | ||
283 | * Returns success (0) or negative errno. | ||
284 | */ | ||
285 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
286 | { | ||
287 | unsigned long flags; | ||
288 | int ret = -EINVAL; | ||
289 | |||
290 | if (!clk || !rate) | ||
291 | return -EFAULT; | ||
292 | |||
293 | if (clk->set_rate) { | ||
294 | spin_lock_irqsave(&clocks_lock, flags); | ||
295 | ret = clk->set_rate(clk, rate); | ||
296 | if (!ret) | ||
297 | /* if successful -> propagate */ | ||
298 | propagate_rate(clk, 0); | ||
299 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
300 | } else if (clk->pclk) { | ||
301 | u32 mult = clk->div_factor ? clk->div_factor : 1; | ||
302 | ret = clk_set_rate(clk->pclk, mult * rate); | ||
303 | } | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | EXPORT_SYMBOL(clk_set_rate); | ||
308 | |||
190 | /* registers clock in platform clock framework */ | 309 | /* registers clock in platform clock framework */ |
191 | void clk_register(struct clk_lookup *cl) | 310 | void clk_register(struct clk_lookup *cl) |
192 | { | 311 | { |
193 | struct clk *clk = cl->clk; | 312 | struct clk *clk; |
194 | unsigned long flags; | 313 | unsigned long flags; |
195 | 314 | ||
196 | if (!clk || IS_ERR(clk)) | 315 | if (!cl || !cl->clk) |
197 | return; | 316 | return; |
317 | clk = cl->clk; | ||
198 | 318 | ||
199 | spin_lock_irqsave(&clocks_lock, flags); | 319 | spin_lock_irqsave(&clocks_lock, flags); |
200 | 320 | ||
@@ -207,71 +327,173 @@ void clk_register(struct clk_lookup *cl) | |||
207 | /* root clock don't have any parents */ | 327 | /* root clock don't have any parents */ |
208 | if (!clk->pclk && !clk->pclk_sel) { | 328 | if (!clk->pclk && !clk->pclk_sel) { |
209 | list_add(&clk->sibling, &root_clks); | 329 | list_add(&clk->sibling, &root_clks); |
210 | /* add clocks with only one parent to parent's children list */ | ||
211 | } else if (clk->pclk && !clk->pclk_sel) { | 330 | } else if (clk->pclk && !clk->pclk_sel) { |
331 | /* add clocks with only one parent to parent's children list */ | ||
212 | list_add(&clk->sibling, &clk->pclk->children); | 332 | list_add(&clk->sibling, &clk->pclk->children); |
213 | } else { | 333 | } else { |
214 | /* add clocks with > 1 parent to 1st parent's children list */ | 334 | /* clocks with more than one parent */ |
215 | list_add(&clk->sibling, | 335 | struct pclk_info *pclk_info; |
216 | &clk->pclk_sel->pclk_info[0].pclk->children); | 336 | |
337 | pclk_info = pclk_info_get(clk); | ||
338 | if (!pclk_info) { | ||
339 | pr_err("CLKDEV: invalid pclk info of clk with" | ||
340 | " %s dev_id and %s con_id\n", | ||
341 | cl->dev_id, cl->con_id); | ||
342 | } else { | ||
343 | clk->pclk = pclk_info->pclk; | ||
344 | list_add(&clk->sibling, &pclk_info->pclk->children); | ||
345 | } | ||
217 | } | 346 | } |
347 | |||
218 | spin_unlock_irqrestore(&clocks_lock, flags); | 348 | spin_unlock_irqrestore(&clocks_lock, flags); |
219 | 349 | ||
350 | /* debugfs specific */ | ||
351 | #ifdef CONFIG_DEBUG_FS | ||
352 | list_add(&clk->node, &clocks); | ||
353 | clk->cl = cl; | ||
354 | #endif | ||
355 | |||
220 | /* add clock to arm clockdev framework */ | 356 | /* add clock to arm clockdev framework */ |
221 | clkdev_add(cl); | 357 | clkdev_add(cl); |
222 | } | 358 | } |
223 | 359 | ||
224 | /** | 360 | /** |
225 | * propagate_rate - recalculate and propagate all clocks in list head | 361 | * propagate_rate - recalculate and propagate all clocks to children |
362 | * @pclk: parent clock required to be propogated | ||
363 | * @on_init: flag for enabling clocks which are ENABLED_ON_INIT. | ||
226 | * | 364 | * |
227 | * Recalculates all root clocks in list head, which if the clock's .recalc is | 365 | * Recalculates all children clocks |
228 | * set correctly, should also propagate their rates. | ||
229 | */ | 366 | */ |
230 | static void propagate_rate(struct list_head *lhead) | 367 | void propagate_rate(struct clk *pclk, int on_init) |
231 | { | 368 | { |
232 | struct clk *clkp, *_temp; | 369 | struct clk *clk, *_temp; |
370 | int ret = 0; | ||
233 | 371 | ||
234 | list_for_each_entry_safe(clkp, _temp, lhead, sibling) { | 372 | list_for_each_entry_safe(clk, _temp, &pclk->children, sibling) { |
235 | if (clkp->recalc) | 373 | if (clk->recalc) { |
236 | clkp->recalc(clkp); | 374 | ret = clk->recalc(clk); |
237 | propagate_rate(&clkp->children); | 375 | /* |
376 | * recalc will return error if clk out is not programmed | ||
377 | * In this case configure default rate. | ||
378 | */ | ||
379 | if (ret && clk->set_rate) | ||
380 | clk->set_rate(clk, 0); | ||
381 | } | ||
382 | propagate_rate(clk, on_init); | ||
383 | |||
384 | if (!on_init) | ||
385 | continue; | ||
386 | |||
387 | /* Enable clks enabled on init, in software view */ | ||
388 | if (clk->flags & ENABLED_ON_INIT) | ||
389 | do_clk_enable(clk); | ||
238 | } | 390 | } |
239 | } | 391 | } |
240 | 392 | ||
241 | /* returns current programmed clocks clock info structure */ | 393 | /** |
242 | static struct pclk_info *pclk_info_get(struct clk *clk) | 394 | * round_rate_index - return closest programmable rate index in rate_config tbl |
395 | * @clk: ptr to clock structure | ||
396 | * @drate: desired rate | ||
397 | * @rate: final rate will be returned in this variable only. | ||
398 | * | ||
399 | * Finds index in rate_config for highest clk rate which is less than | ||
400 | * requested rate. If there is no clk rate lesser than requested rate then | ||
401 | * -EINVAL is returned. This routine assumes that rate_config is written | ||
402 | * in incrementing order of clk rates. | ||
403 | * If drate passed is zero then default rate is programmed. | ||
404 | */ | ||
405 | static int | ||
406 | round_rate_index(struct clk *clk, unsigned long drate, unsigned long *rate) | ||
243 | { | 407 | { |
244 | unsigned int mask, i; | 408 | unsigned long tmp = 0, prev_rate = 0; |
245 | unsigned long flags; | 409 | int index; |
246 | struct pclk_info *info = NULL; | ||
247 | 410 | ||
248 | spin_lock_irqsave(&clocks_lock, flags); | 411 | if (!clk->calc_rate) |
249 | mask = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) | 412 | return -EFAULT; |
250 | & clk->pclk_sel->pclk_sel_mask; | ||
251 | 413 | ||
252 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | 414 | if (!drate) |
253 | if (clk->pclk_sel->pclk_info[i].pclk_mask == mask) | 415 | return -EINVAL; |
254 | info = &clk->pclk_sel->pclk_info[i]; | 416 | |
417 | /* | ||
418 | * This loops ends on two conditions: | ||
419 | * - as soon as clk is found with rate greater than requested rate. | ||
420 | * - if all clks in rate_config are smaller than requested rate. | ||
421 | */ | ||
422 | for (index = 0; index < clk->rate_config.count; index++) { | ||
423 | prev_rate = tmp; | ||
424 | tmp = clk->calc_rate(clk, index); | ||
425 | if (drate < tmp) { | ||
426 | index--; | ||
427 | break; | ||
428 | } | ||
255 | } | 429 | } |
256 | spin_unlock_irqrestore(&clocks_lock, flags); | 430 | /* return if can't find suitable clock */ |
431 | if (index < 0) { | ||
432 | index = -EINVAL; | ||
433 | *rate = 0; | ||
434 | } else if (index == clk->rate_config.count) { | ||
435 | /* program with highest clk rate possible */ | ||
436 | index = clk->rate_config.count - 1; | ||
437 | *rate = tmp; | ||
438 | } else | ||
439 | *rate = prev_rate; | ||
257 | 440 | ||
258 | return info; | 441 | return index; |
259 | } | 442 | } |
260 | 443 | ||
261 | /* | 444 | /** |
262 | * Set pclk as cclk's parent and add clock sibling node to current parents | 445 | * clk_round_rate - adjust a rate to the exact rate a clock can provide |
263 | * children list | 446 | * @clk: clock source |
447 | * @rate: desired clock rate in Hz | ||
448 | * | ||
449 | * Returns rounded clock rate in Hz, or negative errno. | ||
264 | */ | 450 | */ |
265 | static void change_parent(struct clk *cclk, struct clk *pclk) | 451 | long clk_round_rate(struct clk *clk, unsigned long drate) |
266 | { | 452 | { |
267 | unsigned long flags; | 453 | long rate = 0; |
454 | int index; | ||
455 | |||
456 | /* | ||
457 | * propagate call to parent who supports calc_rate. Similar approach is | ||
458 | * used in clk_set_rate. | ||
459 | */ | ||
460 | if (!clk->calc_rate) { | ||
461 | u32 mult; | ||
462 | if (!clk->pclk) | ||
463 | return clk->rate; | ||
464 | |||
465 | mult = clk->div_factor ? clk->div_factor : 1; | ||
466 | return clk_round_rate(clk->pclk, mult * drate) / mult; | ||
467 | } | ||
268 | 468 | ||
269 | spin_lock_irqsave(&clocks_lock, flags); | 469 | index = round_rate_index(clk, drate, &rate); |
270 | list_del(&cclk->sibling); | 470 | if (index >= 0) |
271 | list_add(&cclk->sibling, &pclk->children); | 471 | return rate; |
472 | else | ||
473 | return index; | ||
474 | } | ||
475 | EXPORT_SYMBOL(clk_round_rate); | ||
272 | 476 | ||
273 | cclk->pclk = pclk; | 477 | /*All below functions are called with lock held */ |
274 | spin_unlock_irqrestore(&clocks_lock, flags); | 478 | |
479 | /* | ||
480 | * Calculates pll clk rate for specific value of mode, m, n and p | ||
481 | * | ||
482 | * In normal mode | ||
483 | * rate = (2 * M[15:8] * Fin)/(N * 2^P) | ||
484 | * | ||
485 | * In Dithered mode | ||
486 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) | ||
487 | */ | ||
488 | unsigned long pll_calc_rate(struct clk *clk, int index) | ||
489 | { | ||
490 | unsigned long rate = clk->pclk->rate; | ||
491 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; | ||
492 | unsigned int mode; | ||
493 | |||
494 | mode = tbls[index].mode ? 256 : 1; | ||
495 | return (((2 * rate / 10000) * tbls[index].m) / | ||
496 | (mode * tbls[index].n * (1 << tbls[index].p))) * 10000; | ||
275 | } | 497 | } |
276 | 498 | ||
277 | /* | 499 | /* |
@@ -283,47 +505,146 @@ static void change_parent(struct clk *cclk, struct clk *pclk) | |||
283 | * In Dithered mode | 505 | * In Dithered mode |
284 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) | 506 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) |
285 | */ | 507 | */ |
286 | void pll1_clk_recalc(struct clk *clk) | 508 | int pll_clk_recalc(struct clk *clk) |
287 | { | 509 | { |
288 | struct pll_clk_config *config = clk->private_data; | 510 | struct pll_clk_config *config = clk->private_data; |
289 | unsigned int num = 2, den = 0, val, mode = 0; | 511 | unsigned int num = 2, den = 0, val, mode = 0; |
290 | unsigned long flags; | ||
291 | 512 | ||
292 | spin_lock_irqsave(&clocks_lock, flags); | 513 | mode = (readl(config->mode_reg) >> config->masks->mode_shift) & |
293 | mode = (readl(config->mode_reg) >> PLL_MODE_SHIFT) & | 514 | config->masks->mode_mask; |
294 | PLL_MODE_MASK; | ||
295 | 515 | ||
296 | val = readl(config->cfg_reg); | 516 | val = readl(config->cfg_reg); |
297 | /* calculate denominator */ | 517 | /* calculate denominator */ |
298 | den = (val >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; | 518 | den = (val >> config->masks->div_p_shift) & config->masks->div_p_mask; |
299 | den = 1 << den; | 519 | den = 1 << den; |
300 | den *= (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; | 520 | den *= (val >> config->masks->div_n_shift) & config->masks->div_n_mask; |
301 | 521 | ||
302 | /* calculate numerator & denominator */ | 522 | /* calculate numerator & denominator */ |
303 | if (!mode) { | 523 | if (!mode) { |
304 | /* Normal mode */ | 524 | /* Normal mode */ |
305 | num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; | 525 | num *= (val >> config->masks->norm_fdbk_m_shift) & |
526 | config->masks->norm_fdbk_m_mask; | ||
306 | } else { | 527 | } else { |
307 | /* Dithered mode */ | 528 | /* Dithered mode */ |
308 | num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; | 529 | num *= (val >> config->masks->dith_fdbk_m_shift) & |
530 | config->masks->dith_fdbk_m_mask; | ||
309 | den *= 256; | 531 | den *= 256; |
310 | } | 532 | } |
311 | 533 | ||
534 | if (!den) | ||
535 | return -EINVAL; | ||
536 | |||
312 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; | 537 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; |
313 | spin_unlock_irqrestore(&clocks_lock, flags); | 538 | return 0; |
539 | } | ||
540 | |||
541 | /* | ||
542 | * Configures new clock rate of pll | ||
543 | */ | ||
544 | int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
545 | { | ||
546 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; | ||
547 | struct pll_clk_config *config = clk->private_data; | ||
548 | unsigned long val, rate; | ||
549 | int i; | ||
550 | |||
551 | i = round_rate_index(clk, desired_rate, &rate); | ||
552 | if (i < 0) | ||
553 | return i; | ||
554 | |||
555 | val = readl(config->mode_reg) & | ||
556 | ~(config->masks->mode_mask << config->masks->mode_shift); | ||
557 | val |= (tbls[i].mode & config->masks->mode_mask) << | ||
558 | config->masks->mode_shift; | ||
559 | writel(val, config->mode_reg); | ||
560 | |||
561 | val = readl(config->cfg_reg) & | ||
562 | ~(config->masks->div_p_mask << config->masks->div_p_shift); | ||
563 | val |= (tbls[i].p & config->masks->div_p_mask) << | ||
564 | config->masks->div_p_shift; | ||
565 | val &= ~(config->masks->div_n_mask << config->masks->div_n_shift); | ||
566 | val |= (tbls[i].n & config->masks->div_n_mask) << | ||
567 | config->masks->div_n_shift; | ||
568 | val &= ~(config->masks->dith_fdbk_m_mask << | ||
569 | config->masks->dith_fdbk_m_shift); | ||
570 | if (tbls[i].mode) | ||
571 | val |= (tbls[i].m & config->masks->dith_fdbk_m_mask) << | ||
572 | config->masks->dith_fdbk_m_shift; | ||
573 | else | ||
574 | val |= (tbls[i].m & config->masks->norm_fdbk_m_mask) << | ||
575 | config->masks->norm_fdbk_m_shift; | ||
576 | |||
577 | writel(val, config->cfg_reg); | ||
578 | |||
579 | clk->rate = rate; | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | /* | ||
585 | * Calculates ahb, apb clk rate for specific value of div | ||
586 | */ | ||
587 | unsigned long bus_calc_rate(struct clk *clk, int index) | ||
588 | { | ||
589 | unsigned long rate = clk->pclk->rate; | ||
590 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; | ||
591 | |||
592 | return rate / (tbls[index].div + 1); | ||
314 | } | 593 | } |
315 | 594 | ||
316 | /* calculates current programmed rate of ahb or apb bus */ | 595 | /* calculates current programmed rate of ahb or apb bus */ |
317 | void bus_clk_recalc(struct clk *clk) | 596 | int bus_clk_recalc(struct clk *clk) |
318 | { | 597 | { |
319 | struct bus_clk_config *config = clk->private_data; | 598 | struct bus_clk_config *config = clk->private_data; |
320 | unsigned int div; | 599 | unsigned int div; |
321 | unsigned long flags; | ||
322 | 600 | ||
323 | spin_lock_irqsave(&clocks_lock, flags); | 601 | div = ((readl(config->reg) >> config->masks->shift) & |
324 | div = ((readl(config->reg) >> config->shift) & config->mask) + 1; | 602 | config->masks->mask) + 1; |
603 | |||
604 | if (!div) | ||
605 | return -EINVAL; | ||
606 | |||
325 | clk->rate = (unsigned long)clk->pclk->rate / div; | 607 | clk->rate = (unsigned long)clk->pclk->rate / div; |
326 | spin_unlock_irqrestore(&clocks_lock, flags); | 608 | return 0; |
609 | } | ||
610 | |||
611 | /* Configures new clock rate of AHB OR APB bus */ | ||
612 | int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
613 | { | ||
614 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; | ||
615 | struct bus_clk_config *config = clk->private_data; | ||
616 | unsigned long val, rate; | ||
617 | int i; | ||
618 | |||
619 | i = round_rate_index(clk, desired_rate, &rate); | ||
620 | if (i < 0) | ||
621 | return i; | ||
622 | |||
623 | val = readl(config->reg) & | ||
624 | ~(config->masks->mask << config->masks->shift); | ||
625 | val |= (tbls[i].div & config->masks->mask) << config->masks->shift; | ||
626 | writel(val, config->reg); | ||
627 | |||
628 | clk->rate = rate; | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * gives rate for different values of eq, x and y | ||
635 | * | ||
636 | * Fout from synthesizer can be given from two equations: | ||
637 | * Fout1 = (Fin * X/Y)/2 EQ1 | ||
638 | * Fout2 = Fin * X/Y EQ2 | ||
639 | */ | ||
640 | unsigned long aux_calc_rate(struct clk *clk, int index) | ||
641 | { | ||
642 | unsigned long rate = clk->pclk->rate; | ||
643 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; | ||
644 | u8 eq = tbls[index].eq ? 1 : 2; | ||
645 | |||
646 | return (((rate/10000) * tbls[index].xscale) / | ||
647 | (tbls[index].yscale * eq)) * 10000; | ||
327 | } | 648 | } |
328 | 649 | ||
329 | /* | 650 | /* |
@@ -336,44 +657,76 @@ void bus_clk_recalc(struct clk *clk) | |||
336 | * | 657 | * |
337 | * Selection of eqn 1 or 2 is programmed in register | 658 | * Selection of eqn 1 or 2 is programmed in register |
338 | */ | 659 | */ |
339 | void aux_clk_recalc(struct clk *clk) | 660 | int aux_clk_recalc(struct clk *clk) |
340 | { | 661 | { |
341 | struct aux_clk_config *config = clk->private_data; | 662 | struct aux_clk_config *config = clk->private_data; |
342 | struct pclk_info *pclk_info = NULL; | ||
343 | unsigned int num = 1, den = 1, val, eqn; | 663 | unsigned int num = 1, den = 1, val, eqn; |
344 | unsigned long flags; | ||
345 | 664 | ||
346 | /* get current programmed parent */ | 665 | val = readl(config->synth_reg); |
347 | pclk_info = pclk_info_get(clk); | ||
348 | if (!pclk_info) { | ||
349 | spin_lock_irqsave(&clocks_lock, flags); | ||
350 | clk->pclk = NULL; | ||
351 | clk->rate = 0; | ||
352 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
353 | return; | ||
354 | } | ||
355 | 666 | ||
356 | change_parent(clk, pclk_info->pclk); | 667 | eqn = (val >> config->masks->eq_sel_shift) & |
668 | config->masks->eq_sel_mask; | ||
669 | if (eqn == config->masks->eq1_mask) | ||
670 | den *= 2; | ||
357 | 671 | ||
358 | spin_lock_irqsave(&clocks_lock, flags); | 672 | /* calculate numerator */ |
359 | if (pclk_info->scalable) { | 673 | num = (val >> config->masks->xscale_sel_shift) & |
360 | val = readl(config->synth_reg); | 674 | config->masks->xscale_sel_mask; |
361 | 675 | ||
362 | eqn = (val >> AUX_EQ_SEL_SHIFT) & AUX_EQ_SEL_MASK; | 676 | /* calculate denominator */ |
363 | if (eqn == AUX_EQ1_SEL) | 677 | den *= (val >> config->masks->yscale_sel_shift) & |
364 | den *= 2; | 678 | config->masks->yscale_sel_mask; |
365 | 679 | ||
366 | /* calculate numerator */ | 680 | if (!den) |
367 | num = (val >> AUX_XSCALE_SHIFT) & AUX_XSCALE_MASK; | 681 | return -EINVAL; |
368 | 682 | ||
369 | /* calculate denominator */ | 683 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; |
370 | den *= (val >> AUX_YSCALE_SHIFT) & AUX_YSCALE_MASK; | 684 | return 0; |
371 | val = (((clk->pclk->rate/10000) * num) / den) * 10000; | 685 | } |
372 | } else | ||
373 | val = clk->pclk->rate; | ||
374 | 686 | ||
375 | clk->rate = val; | 687 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ |
376 | spin_unlock_irqrestore(&clocks_lock, flags); | 688 | int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
689 | { | ||
690 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; | ||
691 | struct aux_clk_config *config = clk->private_data; | ||
692 | unsigned long val, rate; | ||
693 | int i; | ||
694 | |||
695 | i = round_rate_index(clk, desired_rate, &rate); | ||
696 | if (i < 0) | ||
697 | return i; | ||
698 | |||
699 | val = readl(config->synth_reg) & | ||
700 | ~(config->masks->eq_sel_mask << config->masks->eq_sel_shift); | ||
701 | val |= (tbls[i].eq & config->masks->eq_sel_mask) << | ||
702 | config->masks->eq_sel_shift; | ||
703 | val &= ~(config->masks->xscale_sel_mask << | ||
704 | config->masks->xscale_sel_shift); | ||
705 | val |= (tbls[i].xscale & config->masks->xscale_sel_mask) << | ||
706 | config->masks->xscale_sel_shift; | ||
707 | val &= ~(config->masks->yscale_sel_mask << | ||
708 | config->masks->yscale_sel_shift); | ||
709 | val |= (tbls[i].yscale & config->masks->yscale_sel_mask) << | ||
710 | config->masks->yscale_sel_shift; | ||
711 | writel(val, config->synth_reg); | ||
712 | |||
713 | clk->rate = rate; | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | /* | ||
719 | * Calculates gpt clk rate for different values of mscale and nscale | ||
720 | * | ||
721 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | ||
722 | */ | ||
723 | unsigned long gpt_calc_rate(struct clk *clk, int index) | ||
724 | { | ||
725 | unsigned long rate = clk->pclk->rate; | ||
726 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; | ||
727 | |||
728 | return rate / ((1 << (tbls[index].nscale + 1)) * | ||
729 | (tbls[index].mscale + 1)); | ||
377 | } | 730 | } |
378 | 731 | ||
379 | /* | 732 | /* |
@@ -381,46 +734,142 @@ void aux_clk_recalc(struct clk *clk) | |||
381 | * Fout from synthesizer can be given from below equations: | 734 | * Fout from synthesizer can be given from below equations: |
382 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | 735 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) |
383 | */ | 736 | */ |
384 | void gpt_clk_recalc(struct clk *clk) | 737 | int gpt_clk_recalc(struct clk *clk) |
385 | { | 738 | { |
386 | struct aux_clk_config *config = clk->private_data; | 739 | struct gpt_clk_config *config = clk->private_data; |
387 | struct pclk_info *pclk_info = NULL; | ||
388 | unsigned int div = 1, val; | 740 | unsigned int div = 1, val; |
389 | unsigned long flags; | ||
390 | 741 | ||
391 | pclk_info = pclk_info_get(clk); | 742 | val = readl(config->synth_reg); |
392 | if (!pclk_info) { | 743 | div += (val >> config->masks->mscale_sel_shift) & |
393 | spin_lock_irqsave(&clocks_lock, flags); | 744 | config->masks->mscale_sel_mask; |
394 | clk->pclk = NULL; | 745 | div *= 1 << (((val >> config->masks->nscale_sel_shift) & |
395 | clk->rate = 0; | 746 | config->masks->nscale_sel_mask) + 1); |
396 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
397 | return; | ||
398 | } | ||
399 | |||
400 | change_parent(clk, pclk_info->pclk); | ||
401 | 747 | ||
402 | spin_lock_irqsave(&clocks_lock, flags); | 748 | if (!div) |
403 | if (pclk_info->scalable) { | 749 | return -EINVAL; |
404 | val = readl(config->synth_reg); | ||
405 | div += (val >> GPT_MSCALE_SHIFT) & GPT_MSCALE_MASK; | ||
406 | div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); | ||
407 | } | ||
408 | 750 | ||
409 | clk->rate = (unsigned long)clk->pclk->rate / div; | 751 | clk->rate = (unsigned long)clk->pclk->rate / div; |
410 | spin_unlock_irqrestore(&clocks_lock, flags); | 752 | return 0; |
753 | } | ||
754 | |||
755 | /* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/ | ||
756 | int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
757 | { | ||
758 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; | ||
759 | struct gpt_clk_config *config = clk->private_data; | ||
760 | unsigned long val, rate; | ||
761 | int i; | ||
762 | |||
763 | i = round_rate_index(clk, desired_rate, &rate); | ||
764 | if (i < 0) | ||
765 | return i; | ||
766 | |||
767 | val = readl(config->synth_reg) & ~(config->masks->mscale_sel_mask << | ||
768 | config->masks->mscale_sel_shift); | ||
769 | val |= (tbls[i].mscale & config->masks->mscale_sel_mask) << | ||
770 | config->masks->mscale_sel_shift; | ||
771 | val &= ~(config->masks->nscale_sel_mask << | ||
772 | config->masks->nscale_sel_shift); | ||
773 | val |= (tbls[i].nscale & config->masks->nscale_sel_mask) << | ||
774 | config->masks->nscale_sel_shift; | ||
775 | writel(val, config->synth_reg); | ||
776 | |||
777 | clk->rate = rate; | ||
778 | |||
779 | return 0; | ||
411 | } | 780 | } |
412 | 781 | ||
413 | /* | 782 | /* |
414 | * Used for clocks that always have same value as the parent clock divided by a | 783 | * Calculates clcd clk rate for different values of div |
784 | * | ||
785 | * Fout from synthesizer can be given from below equation: | ||
786 | * Fout= Fin/2*div (division factor) | ||
787 | * div is 17 bits:- | ||
788 | * 0-13 (fractional part) | ||
789 | * 14-16 (integer part) | ||
790 | * To calculate Fout we left shift val by 14 bits and divide Fin by | ||
791 | * complete div (including fractional part) and then right shift the | ||
792 | * result by 14 places. | ||
793 | */ | ||
794 | unsigned long clcd_calc_rate(struct clk *clk, int index) | ||
795 | { | ||
796 | unsigned long rate = clk->pclk->rate; | ||
797 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; | ||
798 | |||
799 | rate /= 1000; | ||
800 | rate <<= 12; | ||
801 | rate /= (2 * tbls[index].div); | ||
802 | rate >>= 12; | ||
803 | rate *= 1000; | ||
804 | |||
805 | return rate; | ||
806 | } | ||
807 | |||
808 | /* | ||
809 | * calculates current programmed rate of clcd synthesizer | ||
810 | * Fout from synthesizer can be given from below equation: | ||
811 | * Fout= Fin/2*div (division factor) | ||
812 | * div is 17 bits:- | ||
813 | * 0-13 (fractional part) | ||
814 | * 14-16 (integer part) | ||
815 | * To calculate Fout we left shift val by 14 bits and divide Fin by | ||
816 | * complete div (including fractional part) and then right shift the | ||
817 | * result by 14 places. | ||
818 | */ | ||
819 | int clcd_clk_recalc(struct clk *clk) | ||
820 | { | ||
821 | struct clcd_clk_config *config = clk->private_data; | ||
822 | unsigned int div = 1; | ||
823 | unsigned long prate; | ||
824 | unsigned int val; | ||
825 | |||
826 | val = readl(config->synth_reg); | ||
827 | div = (val >> config->masks->div_factor_shift) & | ||
828 | config->masks->div_factor_mask; | ||
829 | |||
830 | if (!div) | ||
831 | return -EINVAL; | ||
832 | |||
833 | prate = clk->pclk->rate / 1000; /* first level division, make it KHz */ | ||
834 | |||
835 | clk->rate = (((unsigned long)prate << 12) / (2 * div)) >> 12; | ||
836 | clk->rate *= 1000; | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ | ||
841 | int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
842 | { | ||
843 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; | ||
844 | struct clcd_clk_config *config = clk->private_data; | ||
845 | unsigned long val, rate; | ||
846 | int i; | ||
847 | |||
848 | i = round_rate_index(clk, desired_rate, &rate); | ||
849 | if (i < 0) | ||
850 | return i; | ||
851 | |||
852 | val = readl(config->synth_reg) & ~(config->masks->div_factor_mask << | ||
853 | config->masks->div_factor_shift); | ||
854 | val |= (tbls[i].div & config->masks->div_factor_mask) << | ||
855 | config->masks->div_factor_shift; | ||
856 | writel(val, config->synth_reg); | ||
857 | |||
858 | clk->rate = rate; | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | /* | ||
864 | * Used for clocks that always have value as the parent clock divided by a | ||
415 | * fixed divisor | 865 | * fixed divisor |
416 | */ | 866 | */ |
417 | void follow_parent(struct clk *clk) | 867 | int follow_parent(struct clk *clk) |
418 | { | 868 | { |
419 | unsigned long flags; | 869 | unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; |
420 | 870 | ||
421 | spin_lock_irqsave(&clocks_lock, flags); | 871 | clk->rate = clk->pclk->rate/div_factor; |
422 | clk->rate = clk->pclk->rate; | 872 | return 0; |
423 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
424 | } | 873 | } |
425 | 874 | ||
426 | /** | 875 | /** |
@@ -431,5 +880,124 @@ void follow_parent(struct clk *clk) | |||
431 | */ | 880 | */ |
432 | void recalc_root_clocks(void) | 881 | void recalc_root_clocks(void) |
433 | { | 882 | { |
434 | propagate_rate(&root_clks); | 883 | struct clk *pclk; |
884 | unsigned long flags; | ||
885 | int ret = 0; | ||
886 | |||
887 | spin_lock_irqsave(&clocks_lock, flags); | ||
888 | list_for_each_entry(pclk, &root_clks, sibling) { | ||
889 | if (pclk->recalc) { | ||
890 | ret = pclk->recalc(pclk); | ||
891 | /* | ||
892 | * recalc will return error if clk out is not programmed | ||
893 | * In this case configure default clock. | ||
894 | */ | ||
895 | if (ret && pclk->set_rate) | ||
896 | pclk->set_rate(pclk, 0); | ||
897 | } | ||
898 | propagate_rate(pclk, 1); | ||
899 | /* Enable clks enabled on init, in software view */ | ||
900 | if (pclk->flags & ENABLED_ON_INIT) | ||
901 | do_clk_enable(pclk); | ||
902 | } | ||
903 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
904 | } | ||
905 | |||
906 | #ifdef CONFIG_DEBUG_FS | ||
907 | /* | ||
908 | * debugfs support to trace clock tree hierarchy and attributes | ||
909 | */ | ||
910 | static struct dentry *clk_debugfs_root; | ||
911 | static int clk_debugfs_register_one(struct clk *c) | ||
912 | { | ||
913 | int err; | ||
914 | struct dentry *d, *child; | ||
915 | struct clk *pa = c->pclk; | ||
916 | char s[255]; | ||
917 | char *p = s; | ||
918 | |||
919 | if (c) { | ||
920 | if (c->cl->con_id) | ||
921 | p += sprintf(p, "%s", c->cl->con_id); | ||
922 | if (c->cl->dev_id) | ||
923 | p += sprintf(p, "%s", c->cl->dev_id); | ||
924 | } | ||
925 | d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); | ||
926 | if (!d) | ||
927 | return -ENOMEM; | ||
928 | c->dent = d; | ||
929 | |||
930 | d = debugfs_create_u32("usage_count", S_IRUGO, c->dent, | ||
931 | (u32 *)&c->usage_count); | ||
932 | if (!d) { | ||
933 | err = -ENOMEM; | ||
934 | goto err_out; | ||
935 | } | ||
936 | d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); | ||
937 | if (!d) { | ||
938 | err = -ENOMEM; | ||
939 | goto err_out; | ||
940 | } | ||
941 | d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); | ||
942 | if (!d) { | ||
943 | err = -ENOMEM; | ||
944 | goto err_out; | ||
945 | } | ||
946 | return 0; | ||
947 | |||
948 | err_out: | ||
949 | d = c->dent; | ||
950 | list_for_each_entry(child, &d->d_subdirs, d_u.d_child) | ||
951 | debugfs_remove(child); | ||
952 | debugfs_remove(c->dent); | ||
953 | return err; | ||
954 | } | ||
955 | |||
956 | static int clk_debugfs_register(struct clk *c) | ||
957 | { | ||
958 | int err; | ||
959 | struct clk *pa = c->pclk; | ||
960 | |||
961 | if (pa && !pa->dent) { | ||
962 | err = clk_debugfs_register(pa); | ||
963 | if (err) | ||
964 | return err; | ||
965 | } | ||
966 | |||
967 | if (!c->dent) { | ||
968 | err = clk_debugfs_register_one(c); | ||
969 | if (err) | ||
970 | return err; | ||
971 | } | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int __init clk_debugfs_init(void) | ||
976 | { | ||
977 | struct clk *c; | ||
978 | struct dentry *d; | ||
979 | int err; | ||
980 | |||
981 | d = debugfs_create_dir("clock", NULL); | ||
982 | if (!d) | ||
983 | return -ENOMEM; | ||
984 | clk_debugfs_root = d; | ||
985 | |||
986 | list_for_each_entry(c, &clocks, node) { | ||
987 | err = clk_debugfs_register(c); | ||
988 | if (err) | ||
989 | goto err_out; | ||
990 | } | ||
991 | return 0; | ||
992 | err_out: | ||
993 | debugfs_remove_recursive(clk_debugfs_root); | ||
994 | return err; | ||
995 | } | ||
996 | late_initcall(clk_debugfs_init); | ||
997 | |||
998 | static int clk_debugfs_reparent(struct clk *c) | ||
999 | { | ||
1000 | debugfs_remove(c->dent); | ||
1001 | return clk_debugfs_register_one(c); | ||
435 | } | 1002 | } |
1003 | #endif /* CONFIG_DEBUG_FS */ | ||
diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h index 2572260f990f..2ae6606930a6 100644 --- a/arch/arm/plat-spear/include/plat/clock.h +++ b/arch/arm/plat-spear/include/plat/clock.h | |||
@@ -21,6 +21,7 @@ | |||
21 | /* clk structure flags */ | 21 | /* clk structure flags */ |
22 | #define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ | 22 | #define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ |
23 | #define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ | 23 | #define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ |
24 | #define ENABLED_ON_INIT (1 << 2) /* clocks enabled at init */ | ||
24 | 25 | ||
25 | /** | 26 | /** |
26 | * struct clkops - clock operations | 27 | * struct clkops - clock operations |
@@ -35,13 +36,11 @@ struct clkops { | |||
35 | /** | 36 | /** |
36 | * struct pclk_info - parents info | 37 | * struct pclk_info - parents info |
37 | * @pclk: pointer to parent clk | 38 | * @pclk: pointer to parent clk |
38 | * @pclk_mask: value to be written for selecting this parent | 39 | * @pclk_val: value to be written for selecting this parent |
39 | * @scalable: Is parent scalable (1 - YES, 0 - NO) | ||
40 | */ | 40 | */ |
41 | struct pclk_info { | 41 | struct pclk_info { |
42 | struct clk *pclk; | 42 | struct clk *pclk; |
43 | u8 pclk_mask; | 43 | u8 pclk_val; |
44 | u8 scalable; | ||
45 | }; | 44 | }; |
46 | 45 | ||
47 | /** | 46 | /** |
@@ -54,11 +53,23 @@ struct pclk_info { | |||
54 | struct pclk_sel { | 53 | struct pclk_sel { |
55 | struct pclk_info *pclk_info; | 54 | struct pclk_info *pclk_info; |
56 | u8 pclk_count; | 55 | u8 pclk_count; |
57 | unsigned int *pclk_sel_reg; | 56 | void __iomem *pclk_sel_reg; |
58 | unsigned int pclk_sel_mask; | 57 | unsigned int pclk_sel_mask; |
59 | }; | 58 | }; |
60 | 59 | ||
61 | /** | 60 | /** |
61 | * struct rate_config - clk rate configurations | ||
62 | * @tbls: array of device specific clk rate tables, in ascending order of rates | ||
63 | * @count: size of tbls array | ||
64 | * @default_index: default setting when originally disabled | ||
65 | */ | ||
66 | struct rate_config { | ||
67 | void *tbls; | ||
68 | u8 count; | ||
69 | u8 default_index; | ||
70 | }; | ||
71 | |||
72 | /** | ||
62 | * struct clk - clock structure | 73 | * struct clk - clock structure |
63 | * @usage_count: num of users who enabled this clock | 74 | * @usage_count: num of users who enabled this clock |
64 | * @flags: flags for clock properties | 75 | * @flags: flags for clock properties |
@@ -67,21 +78,32 @@ struct pclk_sel { | |||
67 | * @en_reg_bit: clk enable/disable bit | 78 | * @en_reg_bit: clk enable/disable bit |
68 | * @ops: clk enable/disable ops - generic_clkops selected if NULL | 79 | * @ops: clk enable/disable ops - generic_clkops selected if NULL |
69 | * @recalc: pointer to clock rate recalculate function | 80 | * @recalc: pointer to clock rate recalculate function |
81 | * @set_rate: pointer to clock set rate function | ||
82 | * @calc_rate: pointer to clock get rate function for index | ||
83 | * @rate_config: rate configuration information, used by set_rate | ||
84 | * @div_factor: division factor to parent clock. | ||
70 | * @pclk: current parent clk | 85 | * @pclk: current parent clk |
71 | * @pclk_sel: pointer to parent selection structure | 86 | * @pclk_sel: pointer to parent selection structure |
72 | * @pclk_sel_shift: register shift for selecting parent of this clock | 87 | * @pclk_sel_shift: register shift for selecting parent of this clock |
73 | * @children: list for childrens or this clock | 88 | * @children: list for childrens or this clock |
74 | * @sibling: node for list of clocks having same parents | 89 | * @sibling: node for list of clocks having same parents |
75 | * @private_data: clock specific private data | 90 | * @private_data: clock specific private data |
91 | * @node: list to maintain clocks linearly | ||
92 | * @cl: clocklook up assoicated with this clock | ||
93 | * @dent: object for debugfs | ||
76 | */ | 94 | */ |
77 | struct clk { | 95 | struct clk { |
78 | unsigned int usage_count; | 96 | unsigned int usage_count; |
79 | unsigned int flags; | 97 | unsigned int flags; |
80 | unsigned long rate; | 98 | unsigned long rate; |
81 | unsigned int *en_reg; | 99 | void __iomem *en_reg; |
82 | u8 en_reg_bit; | 100 | u8 en_reg_bit; |
83 | const struct clkops *ops; | 101 | const struct clkops *ops; |
84 | void (*recalc) (struct clk *); | 102 | int (*recalc) (struct clk *); |
103 | int (*set_rate) (struct clk *, unsigned long rate); | ||
104 | unsigned long (*calc_rate)(struct clk *, int index); | ||
105 | struct rate_config rate_config; | ||
106 | unsigned int div_factor; | ||
85 | 107 | ||
86 | struct clk *pclk; | 108 | struct clk *pclk; |
87 | struct pclk_sel *pclk_sel; | 109 | struct pclk_sel *pclk_sel; |
@@ -90,37 +112,137 @@ struct clk { | |||
90 | struct list_head children; | 112 | struct list_head children; |
91 | struct list_head sibling; | 113 | struct list_head sibling; |
92 | void *private_data; | 114 | void *private_data; |
115 | #ifdef CONFIG_DEBUG_FS | ||
116 | struct list_head node; | ||
117 | struct clk_lookup *cl; | ||
118 | struct dentry *dent; | ||
119 | #endif | ||
93 | }; | 120 | }; |
94 | 121 | ||
95 | /* pll configuration structure */ | 122 | /* pll configuration structure */ |
123 | struct pll_clk_masks { | ||
124 | u32 mode_mask; | ||
125 | u32 mode_shift; | ||
126 | |||
127 | u32 norm_fdbk_m_mask; | ||
128 | u32 norm_fdbk_m_shift; | ||
129 | u32 dith_fdbk_m_mask; | ||
130 | u32 dith_fdbk_m_shift; | ||
131 | u32 div_p_mask; | ||
132 | u32 div_p_shift; | ||
133 | u32 div_n_mask; | ||
134 | u32 div_n_shift; | ||
135 | }; | ||
136 | |||
96 | struct pll_clk_config { | 137 | struct pll_clk_config { |
97 | unsigned int *mode_reg; | 138 | void __iomem *mode_reg; |
98 | unsigned int *cfg_reg; | 139 | void __iomem *cfg_reg; |
140 | struct pll_clk_masks *masks; | ||
141 | }; | ||
142 | |||
143 | /* pll clk rate config structure */ | ||
144 | struct pll_rate_tbl { | ||
145 | u8 mode; | ||
146 | u16 m; | ||
147 | u8 n; | ||
148 | u8 p; | ||
99 | }; | 149 | }; |
100 | 150 | ||
101 | /* ahb and apb bus configuration structure */ | 151 | /* ahb and apb bus configuration structure */ |
152 | struct bus_clk_masks { | ||
153 | u32 mask; | ||
154 | u32 shift; | ||
155 | }; | ||
156 | |||
102 | struct bus_clk_config { | 157 | struct bus_clk_config { |
103 | unsigned int *reg; | 158 | void __iomem *reg; |
104 | unsigned int mask; | 159 | struct bus_clk_masks *masks; |
105 | unsigned int shift; | 160 | }; |
161 | |||
162 | /* ahb and apb clk bus rate config structure */ | ||
163 | struct bus_rate_tbl { | ||
164 | u8 div; | ||
165 | }; | ||
166 | |||
167 | /* Aux clk configuration structure: applicable to UART and FIRDA */ | ||
168 | struct aux_clk_masks { | ||
169 | u32 eq_sel_mask; | ||
170 | u32 eq_sel_shift; | ||
171 | u32 eq1_mask; | ||
172 | u32 eq2_mask; | ||
173 | u32 xscale_sel_mask; | ||
174 | u32 xscale_sel_shift; | ||
175 | u32 yscale_sel_mask; | ||
176 | u32 yscale_sel_shift; | ||
106 | }; | 177 | }; |
107 | 178 | ||
108 | /* | ||
109 | * Aux clk configuration structure: applicable to GPT, UART and FIRDA | ||
110 | */ | ||
111 | struct aux_clk_config { | 179 | struct aux_clk_config { |
112 | unsigned int *synth_reg; | 180 | void __iomem *synth_reg; |
181 | struct aux_clk_masks *masks; | ||
182 | }; | ||
183 | |||
184 | /* aux clk rate config structure */ | ||
185 | struct aux_rate_tbl { | ||
186 | u16 xscale; | ||
187 | u16 yscale; | ||
188 | u8 eq; | ||
189 | }; | ||
190 | |||
191 | /* GPT clk configuration structure */ | ||
192 | struct gpt_clk_masks { | ||
193 | u32 mscale_sel_mask; | ||
194 | u32 mscale_sel_shift; | ||
195 | u32 nscale_sel_mask; | ||
196 | u32 nscale_sel_shift; | ||
197 | }; | ||
198 | |||
199 | struct gpt_clk_config { | ||
200 | void __iomem *synth_reg; | ||
201 | struct gpt_clk_masks *masks; | ||
202 | }; | ||
203 | |||
204 | /* gpt clk rate config structure */ | ||
205 | struct gpt_rate_tbl { | ||
206 | u16 mscale; | ||
207 | u16 nscale; | ||
208 | }; | ||
209 | |||
210 | /* clcd clk configuration structure */ | ||
211 | struct clcd_synth_masks { | ||
212 | u32 div_factor_mask; | ||
213 | u32 div_factor_shift; | ||
214 | }; | ||
215 | |||
216 | struct clcd_clk_config { | ||
217 | void __iomem *synth_reg; | ||
218 | struct clcd_synth_masks *masks; | ||
219 | }; | ||
220 | |||
221 | /* clcd clk rate config structure */ | ||
222 | struct clcd_rate_tbl { | ||
223 | u16 div; | ||
113 | }; | 224 | }; |
114 | 225 | ||
115 | /* platform specific clock functions */ | 226 | /* platform specific clock functions */ |
116 | void clk_register(struct clk_lookup *cl); | 227 | void clk_register(struct clk_lookup *cl); |
117 | void recalc_root_clocks(void); | 228 | void recalc_root_clocks(void); |
118 | 229 | ||
119 | /* clock recalc functions */ | 230 | /* clock recalc & set rate functions */ |
120 | void follow_parent(struct clk *clk); | 231 | int follow_parent(struct clk *clk); |
121 | void pll1_clk_recalc(struct clk *clk); | 232 | unsigned long pll_calc_rate(struct clk *clk, int index); |
122 | void bus_clk_recalc(struct clk *clk); | 233 | int pll_clk_recalc(struct clk *clk); |
123 | void gpt_clk_recalc(struct clk *clk); | 234 | int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate); |
124 | void aux_clk_recalc(struct clk *clk); | 235 | unsigned long bus_calc_rate(struct clk *clk, int index); |
236 | int bus_clk_recalc(struct clk *clk); | ||
237 | int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
238 | unsigned long gpt_calc_rate(struct clk *clk, int index); | ||
239 | int gpt_clk_recalc(struct clk *clk); | ||
240 | int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
241 | unsigned long aux_calc_rate(struct clk *clk, int index); | ||
242 | int aux_clk_recalc(struct clk *clk); | ||
243 | int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
244 | unsigned long clcd_calc_rate(struct clk *clk, int index); | ||
245 | int clcd_clk_recalc(struct clk *clk); | ||
246 | int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
125 | 247 | ||
126 | #endif /* __PLAT_CLOCK_H */ | 248 | #endif /* __PLAT_CLOCK_H */ |
diff --git a/arch/arm/plat-spear/include/plat/debug-macro.S b/arch/arm/plat-spear/include/plat/debug-macro.S index e91270e4f640..8501bbf2c092 100644 --- a/arch/arm/plat-spear/include/plat/debug-macro.S +++ b/arch/arm/plat-spear/include/plat/debug-macro.S | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/amba/serial.h> | 14 | #include <linux/amba/serial.h> |
15 | #include <mach/spear.h> | 15 | #include <mach/hardware.h> |
16 | 16 | ||
17 | .macro addruart, rp, rv | 17 | .macro addruart, rp, rv |
18 | mov \rp, #SPEAR_DBG_UART_BASE @ Physical base | 18 | mov \rp, #SPEAR_DBG_UART_BASE @ Physical base |
diff --git a/arch/arm/plat-spear/include/plat/hardware.h b/arch/arm/plat-spear/include/plat/hardware.h new file mode 100644 index 000000000000..66d677225d15 --- /dev/null +++ b/arch/arm/plat-spear/include/plat/hardware.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * arch/arm/plat-spear/include/plat/hardware.h | ||
3 | * | ||
4 | * Hardware definitions for SPEAr | ||
5 | * | ||
6 | * Copyright (C) 2010 ST Microelectronics | ||
7 | * Viresh Kumar<viresh.kumar@st.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #ifndef __PLAT_HARDWARE_H | ||
15 | #define __PLAT_HARDWARE_H | ||
16 | |||
17 | #ifndef __ASSEMBLY__ | ||
18 | #define IOMEM(x) ((void __iomem __force *)(x)) | ||
19 | #else | ||
20 | #define IOMEM(x) (x) | ||
21 | #endif | ||
22 | |||
23 | #endif /* __PLAT_HARDWARE_H */ | ||
diff --git a/arch/arm/plat-spear/include/plat/memory.h b/arch/arm/plat-spear/include/plat/memory.h index 27a4aba77343..7e3599e1104e 100644 --- a/arch/arm/plat-spear/include/plat/memory.h +++ b/arch/arm/plat-spear/include/plat/memory.h | |||
@@ -15,6 +15,6 @@ | |||
15 | #define __PLAT_MEMORY_H | 15 | #define __PLAT_MEMORY_H |
16 | 16 | ||
17 | /* Physical DRAM offset */ | 17 | /* Physical DRAM offset */ |
18 | #define PHYS_OFFSET UL(0x00000000) | 18 | #define PLAT_PHYS_OFFSET UL(0x00000000) |
19 | 19 | ||
20 | #endif /* __PLAT_MEMORY_H */ | 20 | #endif /* __PLAT_MEMORY_H */ |
diff --git a/arch/arm/plat-spear/include/plat/system.h b/arch/arm/plat-spear/include/plat/system.h index 55a4e405d578..a235fa0ca777 100644 --- a/arch/arm/plat-spear/include/plat/system.h +++ b/arch/arm/plat-spear/include/plat/system.h | |||
@@ -14,9 +14,9 @@ | |||
14 | #ifndef __PLAT_SYSTEM_H | 14 | #ifndef __PLAT_SYSTEM_H |
15 | #define __PLAT_SYSTEM_H | 15 | #define __PLAT_SYSTEM_H |
16 | 16 | ||
17 | #include <asm/hardware/sp810.h> | ||
18 | #include <linux/io.h> | 17 | #include <linux/io.h> |
19 | #include <mach/spear.h> | 18 | #include <asm/hardware/sp810.h> |
19 | #include <mach/hardware.h> | ||
20 | 20 | ||
21 | static inline void arch_idle(void) | 21 | static inline void arch_idle(void) |
22 | { | 22 | { |
diff --git a/arch/arm/plat-spear/include/plat/uncompress.h b/arch/arm/plat-spear/include/plat/uncompress.h index 6dd455bafdfd..1bf84527aee4 100644 --- a/arch/arm/plat-spear/include/plat/uncompress.h +++ b/arch/arm/plat-spear/include/plat/uncompress.h | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/amba/serial.h> | 15 | #include <linux/amba/serial.h> |
16 | #include <mach/spear.h> | 16 | #include <mach/hardware.h> |
17 | 17 | ||
18 | #ifndef __PLAT_UNCOMPRESS_H | 18 | #ifndef __PLAT_UNCOMPRESS_H |
19 | #define __PLAT_UNCOMPRESS_H | 19 | #define __PLAT_UNCOMPRESS_H |
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c index 839c88df9994..dbb6e4fff79d 100644 --- a/arch/arm/plat-spear/time.c +++ b/arch/arm/plat-spear/time.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/plat-spear/time.c | 2 | * arch/arm/plat-spear/time.c |
3 | * | 3 | * |
4 | * Copyright (C) 2009 ST Microelectronics | 4 | * Copyright (C) 2010 ST Microelectronics |
5 | * Shiraz Hashim<shiraz.hashim@st.com> | 5 | * Shiraz Hashim<shiraz.hashim@st.com> |
6 | * | 6 | * |
7 | * This file is licensed under the terms of the GNU General Public | 7 | * This file is licensed under the terms of the GNU General Public |
@@ -20,10 +20,9 @@ | |||
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
21 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
22 | #include <asm/mach/time.h> | 22 | #include <asm/mach/time.h> |
23 | #include <mach/irqs.h> | ||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/spear.h> | ||
26 | #include <mach/generic.h> | 23 | #include <mach/generic.h> |
24 | #include <mach/hardware.h> | ||
25 | #include <mach/irqs.h> | ||
27 | 26 | ||
28 | /* | 27 | /* |
29 | * We would use TIMER0 and TIMER1 as clockevent and clocksource. | 28 | * We would use TIMER0 and TIMER1 as clockevent and clocksource. |
@@ -211,7 +210,7 @@ static void __init spear_clockevent_init(void) | |||
211 | 210 | ||
212 | void __init spear_setup_timer(void) | 211 | void __init spear_setup_timer(void) |
213 | { | 212 | { |
214 | struct clk *pll3_clk; | 213 | int ret; |
215 | 214 | ||
216 | if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) { | 215 | if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) { |
217 | pr_err("%s:cannot get IO addr\n", __func__); | 216 | pr_err("%s:cannot get IO addr\n", __func__); |
@@ -230,26 +229,21 @@ void __init spear_setup_timer(void) | |||
230 | goto err_iomap; | 229 | goto err_iomap; |
231 | } | 230 | } |
232 | 231 | ||
233 | pll3_clk = clk_get(NULL, "pll3_48m_clk"); | 232 | ret = clk_enable(gpt_clk); |
234 | if (!pll3_clk) { | 233 | if (ret < 0) { |
235 | pr_err("%s:couldn't get PLL3 as parent for gpt\n", __func__); | 234 | pr_err("%s:couldn't enable gpt clock\n", __func__); |
236 | goto err_iomap; | 235 | goto err_clk; |
237 | } | 236 | } |
238 | 237 | ||
239 | clk_set_parent(gpt_clk, pll3_clk); | ||
240 | |||
241 | spear_clockevent_init(); | 238 | spear_clockevent_init(); |
242 | spear_clocksource_init(); | 239 | spear_clocksource_init(); |
243 | 240 | ||
244 | return; | 241 | return; |
245 | 242 | ||
243 | err_clk: | ||
244 | clk_put(gpt_clk); | ||
246 | err_iomap: | 245 | err_iomap: |
247 | iounmap(gpt_base); | 246 | iounmap(gpt_base); |
248 | |||
249 | err_mem: | 247 | err_mem: |
250 | release_mem_region(SPEAR_GPT0_BASE, SZ_1K); | 248 | release_mem_region(SPEAR_GPT0_BASE, SZ_1K); |
251 | } | 249 | } |
252 | |||
253 | struct sys_timer spear_sys_timer = { | ||
254 | .init = spear_setup_timer, | ||
255 | }; | ||