aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-stmp3xxx/timer.c
diff options
context:
space:
mode:
authordmitry pervushin <dpervushin@embeddedalley.com>2009-04-23 07:24:13 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-04-27 05:28:08 -0400
commit5cccd37ea15970846a93b4b01fafd6e043bafe8e (patch)
tree4ab99b59f91964028fbba128d8ae086f60bd8c82 /arch/arm/plat-stmp3xxx/timer.c
parente317872ac532fd845c597e55ceb5a9bceee878c1 (diff)
[ARM] 5477/1: Freescale STMP platform support [6/10]
Sources: common STMP3xxx platform support Signed-off-by: dmitry pervushin <dpervushin@embeddedalley.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-stmp3xxx/timer.c')
-rw-r--r--arch/arm/plat-stmp3xxx/timer.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
new file mode 100644
index 000000000000..c916068f0cab
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/timer.c
@@ -0,0 +1,172 @@
1/*
2 * System timer for Freescale STMP37XX/STMP378X
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/clocksource.h>
22#include <linux/clockchips.h>
23#include <linux/io.h>
24#include <linux/irq.h>
25#include <linux/interrupt.h>
26
27#include <asm/mach/time.h>
28#include <mach/stmp3xxx.h>
29#include <mach/regs-timrot.h>
30
31static irqreturn_t
32stmp3xxx_timer_interrupt(int irq, void *dev_id)
33{
34 struct clock_event_device *c = dev_id;
35
36 if (HW_TIMROT_TIMCTRLn_RD(0) & (1<<15)) {
37 HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
38 c->event_handler(c);
39 } else if (HW_TIMROT_TIMCTRLn_RD(1) & (1<<15)) {
40 HW_TIMROT_TIMCTRLn_CLR(1, (1<<15));
41 HW_TIMROT_TIMCTRLn_CLR(1, BM_TIMROT_TIMCTRLn_IRQ_EN);
42 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF);
43 }
44
45 return IRQ_HANDLED;
46}
47
48static cycle_t stmp3xxx_clock_read(void)
49{
50 return ~((HW_TIMROT_TIMCOUNTn_RD(1) & 0xFFFF0000) >> 16);
51}
52
53static int
54stmp3xxx_timrot_set_next_event(unsigned long delta,
55 struct clock_event_device *dev)
56{
57 HW_TIMROT_TIMCOUNTn_WR(0, delta); /* reload */
58 return 0;
59}
60
61static void
62stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
63 struct clock_event_device *dev)
64{
65}
66
67static struct clock_event_device ckevt_timrot = {
68 .name = "timrot",
69 .features = CLOCK_EVT_FEAT_ONESHOT,
70 .shift = 32,
71 .set_next_event = stmp3xxx_timrot_set_next_event,
72 .set_mode = stmp3xxx_timrot_set_mode,
73};
74
75static struct clocksource cksrc_stmp3xxx = {
76 .name = "cksrc_stmp3xxx",
77 .rating = 250,
78 .read = stmp3xxx_clock_read,
79 .mask = CLOCKSOURCE_MASK(16),
80 .shift = 10,
81 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
82};
83
84static struct irqaction stmp3xxx_timer_irq = {
85 .name = "stmp3xxx_timer",
86 .flags = IRQF_DISABLED | IRQF_TIMER,
87 .handler = stmp3xxx_timer_interrupt,
88 .dev_id = &ckevt_timrot,
89};
90
91
92/*
93 * Set up timer interrupt, and return the current time in seconds.
94 */
95static void __init stmp3xxx_init_timer(void)
96{
97 cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
98 cksrc_stmp3xxx.shift);
99 ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
100 ckevt_timrot.shift);
101 ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
102 ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
103 ckevt_timrot.cpumask = cpumask_of(0);
104
105 HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
106 BM_TIMROT_ROTCTRL_CLKGATE);
107 HW_TIMROT_TIMCOUNTn_WR(0, 0);
108 HW_TIMROT_TIMCOUNTn_WR(1, 0);
109
110 HW_TIMROT_TIMCTRLn_WR(0,
111 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
112 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
113 BM_TIMROT_TIMCTRLn_RELOAD |
114 BM_TIMROT_TIMCTRLn_UPDATE |
115 BM_TIMROT_TIMCTRLn_IRQ_EN));
116 HW_TIMROT_TIMCTRLn_WR(1,
117 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
118 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
119 BM_TIMROT_TIMCTRLn_RELOAD |
120 BM_TIMROT_TIMCTRLn_UPDATE));
121
122 HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
123 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
124
125 setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
126
127 clocksource_register(&cksrc_stmp3xxx);
128 clockevents_register_device(&ckevt_timrot);
129}
130
131#ifdef CONFIG_PM
132
133void stmp3xxx_suspend_timer(void)
134{
135 HW_TIMROT_TIMCTRLn_CLR(0, BM_TIMROT_TIMCTRLn_IRQ_EN);
136 HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
137 HW_TIMROT_ROTCTRL_SET(BM_TIMROT_ROTCTRL_CLKGATE);
138}
139
140void stmp3xxx_resume_timer(void)
141{
142 HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
143 BM_TIMROT_ROTCTRL_CLKGATE);
144
145
146 HW_TIMROT_TIMCTRLn_WR(0,
147 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
148 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
149 BM_TIMROT_TIMCTRLn_UPDATE |
150 BM_TIMROT_TIMCTRLn_IRQ_EN));
151 HW_TIMROT_TIMCTRLn_WR(1,
152 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
153 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
154 BM_TIMROT_TIMCTRLn_RELOAD |
155 BM_TIMROT_TIMCTRLn_UPDATE));
156
157 HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
158 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
159}
160
161#else
162
163#define stmp3xxx_suspend_timer NULL
164#define stmp3xxx_resume_timer NULL
165
166#endif /* CONFIG_PM */
167
168struct sys_timer stmp3xxx_timer = {
169 .init = stmp3xxx_init_timer,
170 .suspend = stmp3xxx_suspend_timer,
171 .resume = stmp3xxx_resume_timer,
172};