Merge git://git.infradead.org/battery-2.6
[pandora-kernel.git] / arch / blackfin / kernel / gptimers.c
1 /*
2  * bfin_gptimers.c - derived from bf53x_timers.c
3  *  Driver for General Purpose Timer functions on the Blackfin processor
4  *
5  *  Copyright (C) 2005 John DeHority
6  *  Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
7  *
8  * Licensed under the GPLv2.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13
14 #include <asm/io.h>
15 #include <asm/blackfin.h>
16 #include <asm/gptimers.h>
17
18 #ifdef DEBUG
19 # define tassert(expr)
20 #else
21 # define tassert(expr) \
22         if (!(expr)) \
23                 printk(KERN_DEBUG "%s:%s:%i: Assertion failed: " #expr "\n", \
24                         __FILE__, __func__, __LINE__);
25 #endif
26
27 #define BFIN_TIMER_NUM_GROUP  (BFIN_TIMER_OCTET(MAX_BLACKFIN_GPTIMERS - 1) + 1)
28
29 typedef struct {
30         uint16_t config;
31         uint16_t __pad;
32         uint32_t counter;
33         uint32_t period;
34         uint32_t width;
35 } GPTIMER_timer_regs;
36
37 typedef struct {
38         uint16_t enable;
39         uint16_t __pad0;
40         uint16_t disable;
41         uint16_t __pad1;
42         uint32_t status;
43 } GPTIMER_group_regs;
44
45 static volatile GPTIMER_timer_regs *const timer_regs[MAX_BLACKFIN_GPTIMERS] =
46 {
47         (GPTIMER_timer_regs *)TIMER0_CONFIG,
48         (GPTIMER_timer_regs *)TIMER1_CONFIG,
49         (GPTIMER_timer_regs *)TIMER2_CONFIG,
50 #if (MAX_BLACKFIN_GPTIMERS > 3)
51         (GPTIMER_timer_regs *)TIMER3_CONFIG,
52         (GPTIMER_timer_regs *)TIMER4_CONFIG,
53         (GPTIMER_timer_regs *)TIMER5_CONFIG,
54         (GPTIMER_timer_regs *)TIMER6_CONFIG,
55         (GPTIMER_timer_regs *)TIMER7_CONFIG,
56 #endif
57 #if (MAX_BLACKFIN_GPTIMERS > 8)
58         (GPTIMER_timer_regs *)TIMER8_CONFIG,
59         (GPTIMER_timer_regs *)TIMER9_CONFIG,
60         (GPTIMER_timer_regs *)TIMER10_CONFIG,
61         (GPTIMER_timer_regs *)TIMER11_CONFIG,
62 #endif
63 };
64
65 static volatile GPTIMER_group_regs *const group_regs[BFIN_TIMER_NUM_GROUP] =
66 {
67         (GPTIMER_group_regs *)TIMER0_GROUP_REG,
68 #if (MAX_BLACKFIN_GPTIMERS > 8)
69         (GPTIMER_group_regs *)TIMER8_GROUP_REG,
70 #endif
71 };
72
73 static uint32_t const dis_mask[MAX_BLACKFIN_GPTIMERS] =
74 {
75         TIMER_STATUS_TRUN0,
76         TIMER_STATUS_TRUN1,
77         TIMER_STATUS_TRUN2,
78 #if (MAX_BLACKFIN_GPTIMERS > 3)
79         TIMER_STATUS_TRUN3,
80         TIMER_STATUS_TRUN4,
81         TIMER_STATUS_TRUN5,
82         TIMER_STATUS_TRUN6,
83         TIMER_STATUS_TRUN7,
84 #endif
85 #if (MAX_BLACKFIN_GPTIMERS > 8)
86         TIMER_STATUS_TRUN8,
87         TIMER_STATUS_TRUN9,
88         TIMER_STATUS_TRUN10,
89         TIMER_STATUS_TRUN11,
90 #endif
91 };
92
93 static uint32_t const irq_mask[MAX_BLACKFIN_GPTIMERS] =
94 {
95         TIMER_STATUS_TIMIL0,
96         TIMER_STATUS_TIMIL1,
97         TIMER_STATUS_TIMIL2,
98 #if (MAX_BLACKFIN_GPTIMERS > 3)
99         TIMER_STATUS_TIMIL3,
100         TIMER_STATUS_TIMIL4,
101         TIMER_STATUS_TIMIL5,
102         TIMER_STATUS_TIMIL6,
103         TIMER_STATUS_TIMIL7,
104 #endif
105 #if (MAX_BLACKFIN_GPTIMERS > 8)
106         TIMER_STATUS_TIMIL8,
107         TIMER_STATUS_TIMIL9,
108         TIMER_STATUS_TIMIL10,
109         TIMER_STATUS_TIMIL11,
110 #endif
111 };
112
113 void set_gptimer_pwidth(int timer_id, uint32_t value)
114 {
115         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
116         timer_regs[timer_id]->width = value;
117         SSYNC();
118 }
119 EXPORT_SYMBOL(set_gptimer_pwidth);
120
121 uint32_t get_gptimer_pwidth(int timer_id)
122 {
123         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
124         return timer_regs[timer_id]->width;
125 }
126 EXPORT_SYMBOL(get_gptimer_pwidth);
127
128 void set_gptimer_period(int timer_id, uint32_t period)
129 {
130         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
131         timer_regs[timer_id]->period = period;
132         SSYNC();
133 }
134 EXPORT_SYMBOL(set_gptimer_period);
135
136 uint32_t get_gptimer_period(int timer_id)
137 {
138         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
139         return timer_regs[timer_id]->period;
140 }
141 EXPORT_SYMBOL(get_gptimer_period);
142
143 uint32_t get_gptimer_count(int timer_id)
144 {
145         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
146         return timer_regs[timer_id]->counter;
147 }
148 EXPORT_SYMBOL(get_gptimer_count);
149
150 uint32_t get_gptimer_status(int group)
151 {
152         tassert(group < BFIN_TIMER_NUM_GROUP);
153         return group_regs[group]->status;
154 }
155 EXPORT_SYMBOL(get_gptimer_status);
156
157 void set_gptimer_status(int group, uint32_t value)
158 {
159         tassert(group < BFIN_TIMER_NUM_GROUP);
160         group_regs[group]->status = value;
161         SSYNC();
162 }
163 EXPORT_SYMBOL(set_gptimer_status);
164
165 uint16_t get_gptimer_intr(int timer_id)
166 {
167         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
168         return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & irq_mask[timer_id]) ? 1 : 0;
169 }
170 EXPORT_SYMBOL(get_gptimer_intr);
171
172 void clear_gptimer_intr(int timer_id)
173 {
174         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
175         group_regs[BFIN_TIMER_OCTET(timer_id)]->status = irq_mask[timer_id];
176 }
177 EXPORT_SYMBOL(clear_gptimer_intr);
178
179 void set_gptimer_config(int timer_id, uint16_t config)
180 {
181         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
182         timer_regs[timer_id]->config = config;
183         SSYNC();
184 }
185 EXPORT_SYMBOL(set_gptimer_config);
186
187 uint16_t get_gptimer_config(int timer_id)
188 {
189         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
190         return timer_regs[timer_id]->config;
191 }
192 EXPORT_SYMBOL(get_gptimer_config);
193
194 void enable_gptimers(uint16_t mask)
195 {
196         int i;
197         tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0);
198         for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) {
199                 group_regs[i]->enable = mask & 0xFF;
200                 mask >>= 8;
201         }
202         SSYNC();
203 }
204 EXPORT_SYMBOL(enable_gptimers);
205
206 void disable_gptimers(uint16_t mask)
207 {
208         int i;
209         uint16_t m = mask;
210         tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0);
211         for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) {
212                 group_regs[i]->disable = m & 0xFF;
213                 m >>= 8;
214         }
215         for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i)
216                 if (mask & (1 << i))
217                         group_regs[BFIN_TIMER_OCTET(i)]->status |= dis_mask[i];
218         SSYNC();
219 }
220 EXPORT_SYMBOL(disable_gptimers);
221
222 void set_gptimer_pulse_hi(int timer_id)
223 {
224         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
225         timer_regs[timer_id]->config |= TIMER_PULSE_HI;
226         SSYNC();
227 }
228 EXPORT_SYMBOL(set_gptimer_pulse_hi);
229
230 void clear_gptimer_pulse_hi(int timer_id)
231 {
232         tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
233         timer_regs[timer_id]->config &= ~TIMER_PULSE_HI;
234         SSYNC();
235 }
236 EXPORT_SYMBOL(clear_gptimer_pulse_hi);
237
238 uint16_t get_enabled_gptimers(void)
239 {
240         int i;
241         uint16_t result = 0;
242         for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i)
243                 result |= (group_regs[i]->enable << (i << 3));
244         return result;
245 }
246 EXPORT_SYMBOL(get_enabled_gptimers);
247
248 MODULE_AUTHOR("Axel Weiss (awe@aglaia-gmbh.de)");
249 MODULE_DESCRIPTION("Blackfin General Purpose Timers API");
250 MODULE_LICENSE("GPL");