Blame view
arch/arm/plat-omap/dmtimer.c
19 KB
92105bb70 [ARM] 2887/1: OMA... |
1 2 3 4 5 |
/* * linux/arch/arm/plat-omap/dmtimer.c * * OMAP Dual-Mode Timers * |
97933d6ce ARM: OMAP1: dmtim... |
6 7 8 9 10 11 |
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ * Tarun Kanti DebBarma <tarun.kanti@ti.com> * Thara Gopinath <thara@ti.com> * * dmtimer adaptation to platform_driver. * |
92105bb70 [ARM] 2887/1: OMA... |
12 |
* Copyright (C) 2005 Nokia Corporation |
77900a2fc ARM: OMAP: Port d... |
13 14 |
* OMAP2 support by Juha Yrjola * API improvements and OMAP2 clock framework support by Timo Teras |
92105bb70 [ARM] 2887/1: OMA... |
15 |
* |
44169075e ARM: OMAP4: Add m... |
16 17 18 |
* Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> * |
92105bb70 [ARM] 2887/1: OMA... |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
* This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ |
869dec158 ARM: OMAP: dmtime... |
37 |
#include <linux/module.h> |
fced80c73 [ARM] Convert asm... |
38 |
#include <linux/io.h> |
df28472a1 ARM: OMAP: dmtime... |
39 |
#include <linux/slab.h> |
3392cdd33 ARM: OMAP: dmtime... |
40 |
#include <linux/err.h> |
ffe07ceae ARM: OMAP: dmtime... |
41 |
#include <linux/pm_runtime.h> |
44169075e ARM: OMAP4: Add m... |
42 |
|
3392cdd33 ARM: OMAP: dmtime... |
43 |
#include <plat/dmtimer.h> |
471b3aa70 ARM: OMAP: Pre-34... |
44 |
|
df28472a1 ARM: OMAP: dmtime... |
45 |
static LIST_HEAD(omap_timer_list); |
3392cdd33 ARM: OMAP: dmtime... |
46 |
static DEFINE_SPINLOCK(dm_timer_lock); |
92105bb70 [ARM] 2887/1: OMA... |
47 |
|
3392cdd33 ARM: OMAP: dmtime... |
48 49 50 51 52 53 54 55 |
/** * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode * @timer: timer pointer over which read operation to perform * @reg: lowest byte holds the register offset * * The posted mode bit is encoded in reg. Note that in posted mode write * pending bit must be checked. Otherwise a read of a non completed write * will produce an error. |
0f0d08070 ARM: OMAP: DMTime... |
56 57 |
*/ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) |
77900a2fc ARM: OMAP: Port d... |
58 |
{ |
ee17f1147 ARM: OMAP: Add su... |
59 60 |
WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); return __omap_dm_timer_read(timer, reg, timer->posted); |
77900a2fc ARM: OMAP: Port d... |
61 |
} |
92105bb70 [ARM] 2887/1: OMA... |
62 |
|
3392cdd33 ARM: OMAP: dmtime... |
63 64 65 66 67 68 69 70 71 |
/** * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode * @timer: timer pointer over which write operation is to perform * @reg: lowest byte holds the register offset * @value: data to write into the register * * The posted mode bit is encoded in reg. Note that in posted mode the write * pending bit must be checked. Otherwise a write on a register which has a * pending write will be lost. |
0f0d08070 ARM: OMAP: DMTime... |
72 73 74 |
*/ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, u32 value) |
92105bb70 [ARM] 2887/1: OMA... |
75 |
{ |
ee17f1147 ARM: OMAP: Add su... |
76 77 |
WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); __omap_dm_timer_write(timer, reg, value, timer->posted); |
92105bb70 [ARM] 2887/1: OMA... |
78 |
} |
b481113a8 ARM: OMAP: dmtime... |
79 80 |
static void omap_timer_restore_context(struct omap_dm_timer *timer) { |
b481113a8 ARM: OMAP: dmtime... |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
__raw_writel(timer->context.tisr, timer->irq_stat); omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, timer->context.twer); omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, timer->context.tcrr); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, timer->context.tldr); omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, timer->context.tmar); omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, timer->context.tsicr); __raw_writel(timer->context.tier, timer->irq_ena); omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, timer->context.tclr); } |
77900a2fc ARM: OMAP: Port d... |
96 |
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
97 |
{ |
77900a2fc ARM: OMAP: Port d... |
98 |
int c; |
ee17f1147 ARM: OMAP: Add su... |
99 100 |
if (!timer->sys_stat) return; |
77900a2fc ARM: OMAP: Port d... |
101 |
c = 0; |
ee17f1147 ARM: OMAP: Add su... |
102 |
while (!(__raw_readl(timer->sys_stat) & 1)) { |
77900a2fc ARM: OMAP: Port d... |
103 104 105 106 107 108 109 |
c++; if (c > 100000) { printk(KERN_ERR "Timer failed to reset "); return; } } |
92105bb70 [ARM] 2887/1: OMA... |
110 |
} |
77900a2fc ARM: OMAP: Port d... |
111 112 |
static void omap_dm_timer_reset(struct omap_dm_timer *timer) { |
3392cdd33 ARM: OMAP: dmtime... |
113 |
if (timer->pdev->id != 1) { |
e32f7ec2e ARM: OMAP: Fix 32... |
114 115 116 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); omap_dm_timer_wait_for_reset(timer); } |
0f0d08070 ARM: OMAP: DMTime... |
117 |
|
3392cdd33 ARM: OMAP: dmtime... |
118 |
__omap_dm_timer_reset(timer, 0, 0); |
77900a2fc ARM: OMAP: Port d... |
119 |
} |
3392cdd33 ARM: OMAP: dmtime... |
120 |
int omap_dm_timer_prepare(struct omap_dm_timer *timer) |
77900a2fc ARM: OMAP: Port d... |
121 |
{ |
3392cdd33 ARM: OMAP: dmtime... |
122 |
struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; |
3392cdd33 ARM: OMAP: dmtime... |
123 |
|
506c079b8 ARM: OMAP3+: Impl... |
124 |
omap_dm_timer_enable(timer); |
3392cdd33 ARM: OMAP: dmtime... |
125 126 127 128 129 130 131 |
timer->fclk = clk_get(&timer->pdev->dev, "fck"); if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) { timer->fclk = NULL; dev_err(&timer->pdev->dev, ": No fclk handle. "); return -EINVAL; } |
3392cdd33 ARM: OMAP: dmtime... |
132 133 |
if (pdata->needs_manual_reset) omap_dm_timer_reset(timer); |
506c079b8 ARM: OMAP3+: Impl... |
134 135 |
__omap_dm_timer_enable_posted(timer); omap_dm_timer_disable(timer); |
8c32c4f27 ARM:omap:am33xx: ... |
136 |
return 0; |
77900a2fc ARM: OMAP: Port d... |
137 138 139 140 |
} struct omap_dm_timer *omap_dm_timer_request(void) { |
3392cdd33 ARM: OMAP: dmtime... |
141 |
struct omap_dm_timer *timer = NULL, *t; |
77900a2fc ARM: OMAP: Port d... |
142 |
unsigned long flags; |
3392cdd33 ARM: OMAP: dmtime... |
143 |
int ret = 0; |
77900a2fc ARM: OMAP: Port d... |
144 145 |
spin_lock_irqsave(&dm_timer_lock, flags); |
3392cdd33 ARM: OMAP: dmtime... |
146 147 |
list_for_each_entry(t, &omap_timer_list, node) { if (t->reserved) |
77900a2fc ARM: OMAP: Port d... |
148 |
continue; |
3392cdd33 ARM: OMAP: dmtime... |
149 |
timer = t; |
83379c81f ARM: OMAP: Update... |
150 |
timer->reserved = 1; |
77900a2fc ARM: OMAP: Port d... |
151 152 |
break; } |
3392cdd33 ARM: OMAP: dmtime... |
153 154 155 156 157 158 159 160 |
if (timer) { ret = omap_dm_timer_prepare(timer); if (ret) { timer->reserved = 0; timer = NULL; } } |
77900a2fc ARM: OMAP: Port d... |
161 |
spin_unlock_irqrestore(&dm_timer_lock, flags); |
3392cdd33 ARM: OMAP: dmtime... |
162 163 164 |
if (!timer) pr_debug("%s: timer request failed! ", __func__); |
83379c81f ARM: OMAP: Update... |
165 |
|
77900a2fc ARM: OMAP: Port d... |
166 167 |
return timer; } |
6c366e329 ARM: OMAP: Export... |
168 |
EXPORT_SYMBOL_GPL(omap_dm_timer_request); |
77900a2fc ARM: OMAP: Port d... |
169 170 |
struct omap_dm_timer *omap_dm_timer_request_specific(int id) |
92105bb70 [ARM] 2887/1: OMA... |
171 |
{ |
3392cdd33 ARM: OMAP: dmtime... |
172 |
struct omap_dm_timer *timer = NULL, *t; |
77900a2fc ARM: OMAP: Port d... |
173 |
unsigned long flags; |
3392cdd33 ARM: OMAP: dmtime... |
174 |
int ret = 0; |
92105bb70 [ARM] 2887/1: OMA... |
175 |
|
77900a2fc ARM: OMAP: Port d... |
176 |
spin_lock_irqsave(&dm_timer_lock, flags); |
3392cdd33 ARM: OMAP: dmtime... |
177 178 179 180 181 182 |
list_for_each_entry(t, &omap_timer_list, node) { if (t->pdev->id == id && !t->reserved) { timer = t; timer->reserved = 1; break; } |
77900a2fc ARM: OMAP: Port d... |
183 |
} |
92105bb70 [ARM] 2887/1: OMA... |
184 |
|
3392cdd33 ARM: OMAP: dmtime... |
185 186 187 188 189 190 191 |
if (timer) { ret = omap_dm_timer_prepare(timer); if (ret) { timer->reserved = 0; timer = NULL; } } |
77900a2fc ARM: OMAP: Port d... |
192 |
spin_unlock_irqrestore(&dm_timer_lock, flags); |
3392cdd33 ARM: OMAP: dmtime... |
193 194 195 |
if (!timer) pr_debug("%s: timer%d request failed! ", __func__, id); |
83379c81f ARM: OMAP: Update... |
196 |
|
77900a2fc ARM: OMAP: Port d... |
197 |
return timer; |
92105bb70 [ARM] 2887/1: OMA... |
198 |
} |
6c366e329 ARM: OMAP: Export... |
199 |
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); |
92105bb70 [ARM] 2887/1: OMA... |
200 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
201 |
int omap_dm_timer_free(struct omap_dm_timer *timer) |
77900a2fc ARM: OMAP: Port d... |
202 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
203 204 |
if (unlikely(!timer)) return -EINVAL; |
3392cdd33 ARM: OMAP: dmtime... |
205 |
clk_put(timer->fclk); |
fa4bb626c ARM: OMAP: Use GP... |
206 |
|
77900a2fc ARM: OMAP: Port d... |
207 208 |
WARN_ON(!timer->reserved); timer->reserved = 0; |
ab4eb8b09 ARM: OMAP: dmtime... |
209 |
return 0; |
77900a2fc ARM: OMAP: Port d... |
210 |
} |
6c366e329 ARM: OMAP: Export... |
211 |
EXPORT_SYMBOL_GPL(omap_dm_timer_free); |
77900a2fc ARM: OMAP: Port d... |
212 |
|
12583a70a ARM: OMAP: Add en... |
213 214 |
void omap_dm_timer_enable(struct omap_dm_timer *timer) { |
ffe07ceae ARM: OMAP: dmtime... |
215 |
pm_runtime_get_sync(&timer->pdev->dev); |
12583a70a ARM: OMAP: Add en... |
216 |
} |
6c366e329 ARM: OMAP: Export... |
217 |
EXPORT_SYMBOL_GPL(omap_dm_timer_enable); |
12583a70a ARM: OMAP: Add en... |
218 219 220 |
void omap_dm_timer_disable(struct omap_dm_timer *timer) { |
ffe07ceae ARM: OMAP: dmtime... |
221 |
pm_runtime_put(&timer->pdev->dev); |
12583a70a ARM: OMAP: Add en... |
222 |
} |
6c366e329 ARM: OMAP: Export... |
223 |
EXPORT_SYMBOL_GPL(omap_dm_timer_disable); |
12583a70a ARM: OMAP: Add en... |
224 |
|
77900a2fc ARM: OMAP: Port d... |
225 226 |
int omap_dm_timer_get_irq(struct omap_dm_timer *timer) { |
ab4eb8b09 ARM: OMAP: dmtime... |
227 228 229 |
if (timer) return timer->irq; return -EINVAL; |
77900a2fc ARM: OMAP: Port d... |
230 |
} |
6c366e329 ARM: OMAP: Export... |
231 |
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); |
77900a2fc ARM: OMAP: Port d... |
232 233 |
#if defined(CONFIG_ARCH_OMAP1) |
a569c6ec3 [ARM] 3427/1: ARM... |
234 235 236 237 238 239 |
/** * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR * @inputmask: current value of idlect mask */ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) { |
3392cdd33 ARM: OMAP: dmtime... |
240 241 242 |
int i = 0; struct omap_dm_timer *timer = NULL; unsigned long flags; |
a569c6ec3 [ARM] 3427/1: ARM... |
243 244 245 246 247 248 |
/* If ARMXOR cannot be idled this function call is unnecessary */ if (!(inputmask & (1 << 1))) return inputmask; /* If any active timer is using ARMXOR return modified mask */ |
3392cdd33 ARM: OMAP: dmtime... |
249 250 |
spin_lock_irqsave(&dm_timer_lock, flags); list_for_each_entry(timer, &omap_timer_list, node) { |
77900a2fc ARM: OMAP: Port d... |
251 |
u32 l; |
3392cdd33 ARM: OMAP: dmtime... |
252 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
77900a2fc ARM: OMAP: Port d... |
253 254 |
if (l & OMAP_TIMER_CTRL_ST) { if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) |
a569c6ec3 [ARM] 3427/1: ARM... |
255 256 257 258 |
inputmask &= ~(1 << 1); else inputmask &= ~(1 << 2); } |
3392cdd33 ARM: OMAP: dmtime... |
259 |
i++; |
77900a2fc ARM: OMAP: Port d... |
260 |
} |
3392cdd33 ARM: OMAP: dmtime... |
261 |
spin_unlock_irqrestore(&dm_timer_lock, flags); |
a569c6ec3 [ARM] 3427/1: ARM... |
262 263 264 |
return inputmask; } |
6c366e329 ARM: OMAP: Export... |
265 |
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); |
a569c6ec3 [ARM] 3427/1: ARM... |
266 |
|
140455fa0 omap2/3/4: Replac... |
267 |
#else |
a569c6ec3 [ARM] 3427/1: ARM... |
268 |
|
77900a2fc ARM: OMAP: Port d... |
269 |
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
270 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
271 272 273 |
if (timer) return timer->fclk; return NULL; |
77900a2fc ARM: OMAP: Port d... |
274 |
} |
6c366e329 ARM: OMAP: Export... |
275 |
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk); |
92105bb70 [ARM] 2887/1: OMA... |
276 |
|
77900a2fc ARM: OMAP: Port d... |
277 278 279 |
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) { BUG(); |
2121880e8 ARM: OMAP: Fix wa... |
280 281 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
282 |
} |
6c366e329 ARM: OMAP: Export... |
283 |
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); |
92105bb70 [ARM] 2887/1: OMA... |
284 |
|
77900a2fc ARM: OMAP: Port d... |
285 |
#endif |
92105bb70 [ARM] 2887/1: OMA... |
286 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
287 |
int omap_dm_timer_trigger(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
288 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
289 290 291 292 |
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { pr_err("%s: timer not available or enabled. ", __func__); return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
293 |
} |
77900a2fc ARM: OMAP: Port d... |
294 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
ab4eb8b09 ARM: OMAP: dmtime... |
295 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
296 |
} |
6c366e329 ARM: OMAP: Export... |
297 |
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); |
92105bb70 [ARM] 2887/1: OMA... |
298 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
299 |
int omap_dm_timer_start(struct omap_dm_timer *timer) |
77900a2fc ARM: OMAP: Port d... |
300 301 |
{ u32 l; |
92105bb70 [ARM] 2887/1: OMA... |
302 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
303 304 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
305 306 307 308 309 310 311 312 |
omap_dm_timer_enable(timer); if (timer->loses_context) { u32 ctx_loss_cnt_after = timer->get_context_loss_count(&timer->pdev->dev); if (ctx_loss_cnt_after != timer->ctx_loss_count) omap_timer_restore_context(timer); } |
77900a2fc ARM: OMAP: Port d... |
313 314 315 316 317 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (!(l & OMAP_TIMER_CTRL_ST)) { l |= OMAP_TIMER_CTRL_ST; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } |
b481113a8 ARM: OMAP: dmtime... |
318 319 320 |
/* Save the context */ timer->context.tclr = l; |
ab4eb8b09 ARM: OMAP: dmtime... |
321 |
return 0; |
77900a2fc ARM: OMAP: Port d... |
322 |
} |
6c366e329 ARM: OMAP: Export... |
323 |
EXPORT_SYMBOL_GPL(omap_dm_timer_start); |
92105bb70 [ARM] 2887/1: OMA... |
324 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
325 |
int omap_dm_timer_stop(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
326 |
{ |
caf64f2fd omap: Make a subs... |
327 |
unsigned long rate = 0; |
3392cdd33 ARM: OMAP: dmtime... |
328 |
struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; |
92105bb70 [ARM] 2887/1: OMA... |
329 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
330 331 |
if (unlikely(!timer)) return -EINVAL; |
3392cdd33 ARM: OMAP: dmtime... |
332 333 |
if (!pdata->needs_manual_reset) rate = clk_get_rate(timer->fclk); |
caf64f2fd omap: Make a subs... |
334 |
|
ee17f1147 ARM: OMAP: Add su... |
335 |
__omap_dm_timer_stop(timer, timer->posted, rate); |
ab4eb8b09 ARM: OMAP: dmtime... |
336 337 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
338 |
} |
6c366e329 ARM: OMAP: Export... |
339 |
EXPORT_SYMBOL_GPL(omap_dm_timer_stop); |
92105bb70 [ARM] 2887/1: OMA... |
340 |
|
f248076c0 OMAP2/3 GPTIMER: ... |
341 |
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
92105bb70 [ARM] 2887/1: OMA... |
342 |
{ |
3392cdd33 ARM: OMAP: dmtime... |
343 |
int ret; |
ab4eb8b09 ARM: OMAP: dmtime... |
344 345 346 347 348 349 |
struct dmtimer_platform_data *pdata; if (unlikely(!timer)) return -EINVAL; pdata = timer->pdev->dev.platform_data; |
3392cdd33 ARM: OMAP: dmtime... |
350 |
|
77900a2fc ARM: OMAP: Port d... |
351 |
if (source < 0 || source >= 3) |
f248076c0 OMAP2/3 GPTIMER: ... |
352 |
return -EINVAL; |
77900a2fc ARM: OMAP: Port d... |
353 |
|
3392cdd33 ARM: OMAP: dmtime... |
354 |
ret = pdata->set_timer_src(timer->pdev, source); |
3392cdd33 ARM: OMAP: dmtime... |
355 356 |
return ret; |
92105bb70 [ARM] 2887/1: OMA... |
357 |
} |
6c366e329 ARM: OMAP: Export... |
358 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); |
92105bb70 [ARM] 2887/1: OMA... |
359 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
360 |
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, |
77900a2fc ARM: OMAP: Port d... |
361 |
unsigned int load) |
92105bb70 [ARM] 2887/1: OMA... |
362 363 |
{ u32 l; |
77900a2fc ARM: OMAP: Port d... |
364 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
365 366 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
367 |
omap_dm_timer_enable(timer); |
92105bb70 [ARM] 2887/1: OMA... |
368 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
77900a2fc ARM: OMAP: Port d... |
369 370 371 372 |
if (autoreload) l |= OMAP_TIMER_CTRL_AR; else l &= ~OMAP_TIMER_CTRL_AR; |
92105bb70 [ARM] 2887/1: OMA... |
373 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
77900a2fc ARM: OMAP: Port d... |
374 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); |
0f0d08070 ARM: OMAP: DMTime... |
375 |
|
77900a2fc ARM: OMAP: Port d... |
376 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
b481113a8 ARM: OMAP: dmtime... |
377 378 379 380 |
/* Save the context */ timer->context.tclr = l; timer->context.tldr = load; omap_dm_timer_disable(timer); |
ab4eb8b09 ARM: OMAP: dmtime... |
381 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
382 |
} |
6c366e329 ARM: OMAP: Export... |
383 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load); |
92105bb70 [ARM] 2887/1: OMA... |
384 |
|
3fddd09e5 ARM: OMAP: DMTime... |
385 |
/* Optimized set_load which removes costly spin wait in timer_start */ |
ab4eb8b09 ARM: OMAP: dmtime... |
386 |
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, |
3fddd09e5 ARM: OMAP: DMTime... |
387 388 389 |
unsigned int load) { u32 l; |
ab4eb8b09 ARM: OMAP: dmtime... |
390 391 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
392 393 394 395 396 397 398 399 |
omap_dm_timer_enable(timer); if (timer->loses_context) { u32 ctx_loss_cnt_after = timer->get_context_loss_count(&timer->pdev->dev); if (ctx_loss_cnt_after != timer->ctx_loss_count) omap_timer_restore_context(timer); } |
3fddd09e5 ARM: OMAP: DMTime... |
400 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
64ce2907b ARM: OMAP2: skip ... |
401 |
if (autoreload) { |
3fddd09e5 ARM: OMAP: DMTime... |
402 |
l |= OMAP_TIMER_CTRL_AR; |
64ce2907b ARM: OMAP2: skip ... |
403 404 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); } else { |
3fddd09e5 ARM: OMAP: DMTime... |
405 |
l &= ~OMAP_TIMER_CTRL_AR; |
64ce2907b ARM: OMAP2: skip ... |
406 |
} |
3fddd09e5 ARM: OMAP: DMTime... |
407 |
l |= OMAP_TIMER_CTRL_ST; |
ee17f1147 ARM: OMAP: Add su... |
408 |
__omap_dm_timer_load_start(timer, l, load, timer->posted); |
b481113a8 ARM: OMAP: dmtime... |
409 410 411 412 413 |
/* Save the context */ timer->context.tclr = l; timer->context.tldr = load; timer->context.tcrr = load; |
ab4eb8b09 ARM: OMAP: dmtime... |
414 |
return 0; |
3fddd09e5 ARM: OMAP: DMTime... |
415 |
} |
6c366e329 ARM: OMAP: Export... |
416 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); |
3fddd09e5 ARM: OMAP: DMTime... |
417 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
418 |
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
77900a2fc ARM: OMAP: Port d... |
419 |
unsigned int match) |
92105bb70 [ARM] 2887/1: OMA... |
420 421 |
{ u32 l; |
ab4eb8b09 ARM: OMAP: dmtime... |
422 423 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
424 |
omap_dm_timer_enable(timer); |
92105bb70 [ARM] 2887/1: OMA... |
425 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
83379c81f ARM: OMAP: Update... |
426 |
if (enable) |
77900a2fc ARM: OMAP: Port d... |
427 428 429 |
l |= OMAP_TIMER_CTRL_CE; else l &= ~OMAP_TIMER_CTRL_CE; |
92105bb70 [ARM] 2887/1: OMA... |
430 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
77900a2fc ARM: OMAP: Port d... |
431 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); |
b481113a8 ARM: OMAP: dmtime... |
432 433 434 435 436 |
/* Save the context */ timer->context.tclr = l; timer->context.tmar = match; omap_dm_timer_disable(timer); |
ab4eb8b09 ARM: OMAP: dmtime... |
437 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
438 |
} |
6c366e329 ARM: OMAP: Export... |
439 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); |
92105bb70 [ARM] 2887/1: OMA... |
440 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
441 |
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, |
77900a2fc ARM: OMAP: Port d... |
442 |
int toggle, int trigger) |
92105bb70 [ARM] 2887/1: OMA... |
443 444 |
{ u32 l; |
ab4eb8b09 ARM: OMAP: dmtime... |
445 446 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
447 |
omap_dm_timer_enable(timer); |
92105bb70 [ARM] 2887/1: OMA... |
448 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
77900a2fc ARM: OMAP: Port d... |
449 450 451 452 453 454 455 |
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | OMAP_TIMER_CTRL_PT | (0x03 << 10)); if (def_on) l |= OMAP_TIMER_CTRL_SCPWM; if (toggle) l |= OMAP_TIMER_CTRL_PT; l |= trigger << 10; |
92105bb70 [ARM] 2887/1: OMA... |
456 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
b481113a8 ARM: OMAP: dmtime... |
457 458 459 460 |
/* Save the context */ timer->context.tclr = l; omap_dm_timer_disable(timer); |
ab4eb8b09 ARM: OMAP: dmtime... |
461 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
462 |
} |
6c366e329 ARM: OMAP: Export... |
463 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm); |
92105bb70 [ARM] 2887/1: OMA... |
464 |
|
8c32c4f27 ARM:omap:am33xx: ... |
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
int omap_dm_timer_set_capture(struct omap_dm_timer *timer, bool lht, bool hlt, bool cm) { u32 l; if (unlikely(!timer)) return -EINVAL; omap_dm_timer_enable(timer); l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (lht && hlt) l |= OMAP_TIMER_CTRL_TCM_BOTHEDGES; else if (lht) l |= OMAP_TIMER_CTRL_TCM_LOWTOHIGH; else if (hlt) l |= OMAP_TIMER_CTRL_TCM_HIGHTOLOW; else l &= ~OMAP_TIMER_CTRL_TCM_BOTHEDGES; if (cm) l |= OMAP_TIMER_CTRL_CAPTMODE; else l &= ~OMAP_TIMER_CTRL_CAPTMODE; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); /* Save the context */ timer->context.tclr = l; omap_dm_timer_disable(timer); return 0; } EXPORT_SYMBOL_GPL(omap_dm_timer_set_capture); |
ab4eb8b09 ARM: OMAP: dmtime... |
498 |
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) |
92105bb70 [ARM] 2887/1: OMA... |
499 500 |
{ u32 l; |
ab4eb8b09 ARM: OMAP: dmtime... |
501 502 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
503 |
omap_dm_timer_enable(timer); |
92105bb70 [ARM] 2887/1: OMA... |
504 |
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
77900a2fc ARM: OMAP: Port d... |
505 506 507 508 509 |
l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); if (prescaler >= 0x00 && prescaler <= 0x07) { l |= OMAP_TIMER_CTRL_PRE; l |= prescaler << 2; } |
92105bb70 [ARM] 2887/1: OMA... |
510 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
b481113a8 ARM: OMAP: dmtime... |
511 512 513 514 |
/* Save the context */ timer->context.tclr = l; omap_dm_timer_disable(timer); |
ab4eb8b09 ARM: OMAP: dmtime... |
515 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
516 |
} |
6c366e329 ARM: OMAP: Export... |
517 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); |
92105bb70 [ARM] 2887/1: OMA... |
518 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
519 |
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, |
77900a2fc ARM: OMAP: Port d... |
520 |
unsigned int value) |
92105bb70 [ARM] 2887/1: OMA... |
521 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
522 523 |
if (unlikely(!timer)) return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
524 |
omap_dm_timer_enable(timer); |
ee17f1147 ARM: OMAP: Add su... |
525 |
__omap_dm_timer_int_enable(timer, value); |
b481113a8 ARM: OMAP: dmtime... |
526 527 528 529 530 |
/* Save the context */ timer->context.tier = value; timer->context.twer = value; omap_dm_timer_disable(timer); |
ab4eb8b09 ARM: OMAP: dmtime... |
531 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
532 |
} |
6c366e329 ARM: OMAP: Export... |
533 |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); |
92105bb70 [ARM] 2887/1: OMA... |
534 |
|
77900a2fc ARM: OMAP: Port d... |
535 |
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
536 |
{ |
fa4bb626c ARM: OMAP: Use GP... |
537 |
unsigned int l; |
ab4eb8b09 ARM: OMAP: dmtime... |
538 539 540 |
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { pr_err("%s: timer not available or enabled. ", __func__); |
b481113a8 ARM: OMAP: dmtime... |
541 542 |
return 0; } |
ee17f1147 ARM: OMAP: Add su... |
543 |
l = __raw_readl(timer->irq_stat); |
fa4bb626c ARM: OMAP: Use GP... |
544 545 |
return l; |
92105bb70 [ARM] 2887/1: OMA... |
546 |
} |
6c366e329 ARM: OMAP: Export... |
547 |
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); |
92105bb70 [ARM] 2887/1: OMA... |
548 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
549 |
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
92105bb70 [ARM] 2887/1: OMA... |
550 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
551 552 |
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) return -EINVAL; |
ee17f1147 ARM: OMAP: Add su... |
553 |
__omap_dm_timer_write_status(timer, value); |
b481113a8 ARM: OMAP: dmtime... |
554 555 |
/* Save the context */ timer->context.tisr = value; |
ab4eb8b09 ARM: OMAP: dmtime... |
556 |
return 0; |
92105bb70 [ARM] 2887/1: OMA... |
557 |
} |
6c366e329 ARM: OMAP: Export... |
558 |
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); |
92105bb70 [ARM] 2887/1: OMA... |
559 |
|
77900a2fc ARM: OMAP: Port d... |
560 |
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
92105bb70 [ARM] 2887/1: OMA... |
561 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
562 563 564 |
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { pr_err("%s: timer not iavailable or enabled. ", __func__); |
b481113a8 ARM: OMAP: dmtime... |
565 566 |
return 0; } |
ee17f1147 ARM: OMAP: Add su... |
567 |
return __omap_dm_timer_read_counter(timer, timer->posted); |
92105bb70 [ARM] 2887/1: OMA... |
568 |
} |
6c366e329 ARM: OMAP: Export... |
569 |
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); |
92105bb70 [ARM] 2887/1: OMA... |
570 |
|
ab4eb8b09 ARM: OMAP: dmtime... |
571 |
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) |
83379c81f ARM: OMAP: Update... |
572 |
{ |
ab4eb8b09 ARM: OMAP: dmtime... |
573 574 575 576 |
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { pr_err("%s: timer not available or enabled. ", __func__); return -EINVAL; |
b481113a8 ARM: OMAP: dmtime... |
577 |
} |
fa4bb626c ARM: OMAP: Use GP... |
578 |
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); |
b481113a8 ARM: OMAP: dmtime... |
579 580 581 |
/* Save the context */ timer->context.tcrr = value; |
ab4eb8b09 ARM: OMAP: dmtime... |
582 |
return 0; |
83379c81f ARM: OMAP: Update... |
583 |
} |
6c366e329 ARM: OMAP: Export... |
584 |
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter); |
83379c81f ARM: OMAP: Update... |
585 |
|
77900a2fc ARM: OMAP: Port d... |
586 |
int omap_dm_timers_active(void) |
92105bb70 [ARM] 2887/1: OMA... |
587 |
{ |
3392cdd33 ARM: OMAP: dmtime... |
588 |
struct omap_dm_timer *timer; |
12583a70a ARM: OMAP: Add en... |
589 |
|
3392cdd33 ARM: OMAP: dmtime... |
590 |
list_for_each_entry(timer, &omap_timer_list, node) { |
ffe07ceae ARM: OMAP: dmtime... |
591 |
if (!timer->reserved) |
12583a70a ARM: OMAP: Add en... |
592 |
continue; |
77900a2fc ARM: OMAP: Port d... |
593 |
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & |
fa4bb626c ARM: OMAP: Use GP... |
594 |
OMAP_TIMER_CTRL_ST) { |
77900a2fc ARM: OMAP: Port d... |
595 |
return 1; |
fa4bb626c ARM: OMAP: Use GP... |
596 |
} |
77900a2fc ARM: OMAP: Port d... |
597 598 599 |
} return 0; } |
6c366e329 ARM: OMAP: Export... |
600 |
EXPORT_SYMBOL_GPL(omap_dm_timers_active); |
92105bb70 [ARM] 2887/1: OMA... |
601 |
|
df28472a1 ARM: OMAP: dmtime... |
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
/** * omap_dm_timer_probe - probe function called for every registered device * @pdev: pointer to current timer platform device * * Called by driver framework at the end of device registration for all * timer devices. */ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) { int ret; unsigned long flags; struct omap_dm_timer *timer; struct resource *mem, *irq, *ioarea; struct dmtimer_platform_data *pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "%s: no platform data. ", __func__); return -ENODEV; } irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!irq)) { dev_err(&pdev->dev, "%s: no IRQ resource. ", __func__); return -ENODEV; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!mem)) { dev_err(&pdev->dev, "%s: no memory resource. ", __func__); return -ENODEV; } ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name); if (!ioarea) { dev_err(&pdev->dev, "%s: region already claimed. ", __func__); return -EBUSY; } timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL); if (!timer) { dev_err(&pdev->dev, "%s: no memory for omap_dm_timer. ", __func__); ret = -ENOMEM; goto err_free_ioregion; } timer->io_base = ioremap(mem->start, resource_size(mem)); if (!timer->io_base) { dev_err(&pdev->dev, "%s: ioremap failed. ", __func__); ret = -ENOMEM; goto err_free_mem; } timer->id = pdev->id; |
506c079b8 ARM: OMAP3+: Impl... |
663 |
timer->errata = pdata->timer_errata; |
df28472a1 ARM: OMAP: dmtime... |
664 |
timer->irq = irq->start; |
0dad9faea ARM: OMAP: dmtime... |
665 |
timer->reserved = pdata->reserved; |
df28472a1 ARM: OMAP: dmtime... |
666 |
timer->pdev = pdev; |
b481113a8 ARM: OMAP: dmtime... |
667 668 |
timer->loses_context = pdata->loses_context; timer->get_context_loss_count = pdata->get_context_loss_count; |
df28472a1 ARM: OMAP: dmtime... |
669 |
|
ffe07ceae ARM: OMAP: dmtime... |
670 671 672 673 674 |
/* Skip pm_runtime_enable for OMAP1 */ if (!pdata->needs_manual_reset) { pm_runtime_enable(&pdev->dev); pm_runtime_irq_safe(&pdev->dev); } |
0dad9faea ARM: OMAP: dmtime... |
675 676 677 678 679 |
if (!timer->reserved) { pm_runtime_get_sync(&pdev->dev); __omap_dm_timer_init_regs(timer); pm_runtime_put(&pdev->dev); } |
df28472a1 ARM: OMAP: dmtime... |
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
/* add the timer element to the list */ spin_lock_irqsave(&dm_timer_lock, flags); list_add_tail(&timer->node, &omap_timer_list); spin_unlock_irqrestore(&dm_timer_lock, flags); dev_dbg(&pdev->dev, "Device Probed. "); return 0; err_free_mem: kfree(timer); err_free_ioregion: release_mem_region(mem->start, resource_size(mem)); return ret; } /** * omap_dm_timer_remove - cleanup a registered timer device * @pdev: pointer to current timer platform device * * Called by driver framework whenever a timer device is unregistered. * In addition to freeing platform resources it also deletes the timer * entry from the local list. */ static int __devexit omap_dm_timer_remove(struct platform_device *pdev) { struct omap_dm_timer *timer; unsigned long flags; int ret = -EINVAL; spin_lock_irqsave(&dm_timer_lock, flags); list_for_each_entry(timer, &omap_timer_list, node) if (timer->pdev->id == pdev->id) { list_del(&timer->node); kfree(timer); ret = 0; break; } spin_unlock_irqrestore(&dm_timer_lock, flags); return ret; } static struct platform_driver omap_dm_timer_driver = { .probe = omap_dm_timer_probe, |
4c23c8da9 ARM: omap: use __... |
728 |
.remove = __devexit_p(omap_dm_timer_remove), |
df28472a1 ARM: OMAP: dmtime... |
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
.driver = { .name = "omap_timer", }, }; static int __init omap_dm_timer_driver_init(void) { return platform_driver_register(&omap_dm_timer_driver); } static void __exit omap_dm_timer_driver_exit(void) { platform_driver_unregister(&omap_dm_timer_driver); } early_platform_init("earlytimer", &omap_dm_timer_driver); module_init(omap_dm_timer_driver_init); module_exit(omap_dm_timer_driver_exit); MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Texas Instruments Inc"); |