diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/clock.c')
-rw-r--r-- | arch/avr32/mach-at32ap/clock.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c new file mode 100644 index 000000000000..3d0d1097389f --- /dev/null +++ b/arch/avr32/mach-at32ap/clock.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Clock management for AT32AP CPUs | ||
3 | * | ||
4 | * Copyright (C) 2006 Atmel Corporation | ||
5 | * | ||
6 | * Based on arch/arm/mach-at91rm9200/clock.c | ||
7 | * Copyright (C) 2005 David Brownell | ||
8 | * Copyright (C) 2005 Ivan Kokshaysky | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/string.h> | ||
18 | |||
19 | #include "clock.h" | ||
20 | |||
21 | static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED; | ||
22 | |||
23 | struct clk *clk_get(struct device *dev, const char *id) | ||
24 | { | ||
25 | int i; | ||
26 | |||
27 | for (i = 0; i < at32_nr_clocks; i++) { | ||
28 | struct clk *clk = at32_clock_list[i]; | ||
29 | |||
30 | if (clk->dev == dev && strcmp(id, clk->name) == 0) | ||
31 | return clk; | ||
32 | } | ||
33 | |||
34 | return ERR_PTR(-ENOENT); | ||
35 | } | ||
36 | EXPORT_SYMBOL(clk_get); | ||
37 | |||
38 | void clk_put(struct clk *clk) | ||
39 | { | ||
40 | /* clocks are static for now, we can't free them */ | ||
41 | } | ||
42 | EXPORT_SYMBOL(clk_put); | ||
43 | |||
44 | static void __clk_enable(struct clk *clk) | ||
45 | { | ||
46 | if (clk->parent) | ||
47 | __clk_enable(clk->parent); | ||
48 | if (clk->users++ == 0 && clk->mode) | ||
49 | clk->mode(clk, 1); | ||
50 | } | ||
51 | |||
52 | int clk_enable(struct clk *clk) | ||
53 | { | ||
54 | unsigned long flags; | ||
55 | |||
56 | spin_lock_irqsave(&clk_lock, flags); | ||
57 | __clk_enable(clk); | ||
58 | spin_unlock_irqrestore(&clk_lock, flags); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | EXPORT_SYMBOL(clk_enable); | ||
63 | |||
64 | static void __clk_disable(struct clk *clk) | ||
65 | { | ||
66 | BUG_ON(clk->users == 0); | ||
67 | |||
68 | if (--clk->users == 0 && clk->mode) | ||
69 | clk->mode(clk, 0); | ||
70 | if (clk->parent) | ||
71 | __clk_disable(clk->parent); | ||
72 | } | ||
73 | |||
74 | void clk_disable(struct clk *clk) | ||
75 | { | ||
76 | unsigned long flags; | ||
77 | |||
78 | spin_lock_irqsave(&clk_lock, flags); | ||
79 | __clk_disable(clk); | ||
80 | spin_unlock_irqrestore(&clk_lock, flags); | ||
81 | } | ||
82 | EXPORT_SYMBOL(clk_disable); | ||
83 | |||
84 | unsigned long clk_get_rate(struct clk *clk) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | unsigned long rate; | ||
88 | |||
89 | spin_lock_irqsave(&clk_lock, flags); | ||
90 | rate = clk->get_rate(clk); | ||
91 | spin_unlock_irqrestore(&clk_lock, flags); | ||
92 | |||
93 | return rate; | ||
94 | } | ||
95 | EXPORT_SYMBOL(clk_get_rate); | ||
96 | |||
97 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
98 | { | ||
99 | unsigned long flags, actual_rate; | ||
100 | |||
101 | if (!clk->set_rate) | ||
102 | return -ENOSYS; | ||
103 | |||
104 | spin_lock_irqsave(&clk_lock, flags); | ||
105 | actual_rate = clk->set_rate(clk, rate, 0); | ||
106 | spin_unlock_irqrestore(&clk_lock, flags); | ||
107 | |||
108 | return actual_rate; | ||
109 | } | ||
110 | EXPORT_SYMBOL(clk_round_rate); | ||
111 | |||
112 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
113 | { | ||
114 | unsigned long flags; | ||
115 | long ret; | ||
116 | |||
117 | if (!clk->set_rate) | ||
118 | return -ENOSYS; | ||
119 | |||
120 | spin_lock_irqsave(&clk_lock, flags); | ||
121 | ret = clk->set_rate(clk, rate, 1); | ||
122 | spin_unlock_irqrestore(&clk_lock, flags); | ||
123 | |||
124 | return (ret < 0) ? ret : 0; | ||
125 | } | ||
126 | EXPORT_SYMBOL(clk_set_rate); | ||
127 | |||
128 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
129 | { | ||
130 | unsigned long flags; | ||
131 | int ret; | ||
132 | |||
133 | if (!clk->set_parent) | ||
134 | return -ENOSYS; | ||
135 | |||
136 | spin_lock_irqsave(&clk_lock, flags); | ||
137 | ret = clk->set_parent(clk, parent); | ||
138 | spin_unlock_irqrestore(&clk_lock, flags); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | EXPORT_SYMBOL(clk_set_parent); | ||
143 | |||
144 | struct clk *clk_get_parent(struct clk *clk) | ||
145 | { | ||
146 | return clk->parent; | ||
147 | } | ||
148 | EXPORT_SYMBOL(clk_get_parent); | ||