diff options
author | dmitry pervushin <dpervushin@embeddedalley.com> | 2009-04-23 07:24:13 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-04-27 05:28:08 -0400 |
commit | 5cccd37ea15970846a93b4b01fafd6e043bafe8e (patch) | |
tree | 4ab99b59f91964028fbba128d8ae086f60bd8c82 /arch/arm/plat-stmp3xxx/timer.c | |
parent | e317872ac532fd845c597e55ceb5a9bceee878c1 (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.c | 172 |
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 | |||
31 | static irqreturn_t | ||
32 | stmp3xxx_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 | |||
48 | static cycle_t stmp3xxx_clock_read(void) | ||
49 | { | ||
50 | return ~((HW_TIMROT_TIMCOUNTn_RD(1) & 0xFFFF0000) >> 16); | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | stmp3xxx_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 | |||
61 | static void | ||
62 | stmp3xxx_timrot_set_mode(enum clock_event_mode mode, | ||
63 | struct clock_event_device *dev) | ||
64 | { | ||
65 | } | ||
66 | |||
67 | static 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 | |||
75 | static 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 | |||
84 | static 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 | */ | ||
95 | static 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 | |||
133 | void 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 | |||
140 | void 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 | |||
168 | struct sys_timer stmp3xxx_timer = { | ||
169 | .init = stmp3xxx_init_timer, | ||
170 | .suspend = stmp3xxx_suspend_timer, | ||
171 | .resume = stmp3xxx_resume_timer, | ||
172 | }; | ||