Commit d4905ce38c73964b868037e49a5945e1cf47a7f2
1 parent
db7eba292e
Exists in
master
and in
7 other branches
Revert "clocksource: sh_tmu: Runtime PM support"
This reverts commit 1b842e91fea9447eff5eb687e28ad61c02f5033e. There is a fundamental ordering race between the early and late probe paths and the runtime PM tie-in that results in __pm_runtime_resume() attempting to take a lock that hasn't been initialized yet (which by proxy also suggests that pm_runtime_init() hasn't yet been run on the device either, making the entire thing unsafe) -- resulting in instant death on SMP or on UP with spinlock debugging enabled: sh_tmu.0: used for clock events sh_tmu.0: used for periodic clock events BUG: spinlock trylock failure on UP on CPU#0, swapper/0 lock: 804db198, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0 ... Revert it for now until the ordering issues can be resolved, or we can get some more help from the runtime PM framework to make this possible. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 1 changed file with 2 additions and 10 deletions Inline Diff
drivers/clocksource/sh_tmu.c
1 | /* | 1 | /* |
2 | * SuperH Timer Support - TMU | 2 | * SuperH Timer Support - TMU |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Magnus Damm | 4 | * Copyright (C) 2009 Magnus Damm |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License | 8 | * the Free Software Foundation; either version 2 of the License |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/pm_runtime.h> | ||
29 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
30 | #include <linux/err.h> | 29 | #include <linux/err.h> |
31 | #include <linux/clocksource.h> | 30 | #include <linux/clocksource.h> |
32 | #include <linux/clockchips.h> | 31 | #include <linux/clockchips.h> |
33 | #include <linux/sh_timer.h> | 32 | #include <linux/sh_timer.h> |
34 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
35 | 34 | ||
36 | struct sh_tmu_priv { | 35 | struct sh_tmu_priv { |
37 | void __iomem *mapbase; | 36 | void __iomem *mapbase; |
38 | struct clk *clk; | 37 | struct clk *clk; |
39 | struct irqaction irqaction; | 38 | struct irqaction irqaction; |
40 | struct platform_device *pdev; | 39 | struct platform_device *pdev; |
41 | unsigned long rate; | 40 | unsigned long rate; |
42 | unsigned long periodic; | 41 | unsigned long periodic; |
43 | struct clock_event_device ced; | 42 | struct clock_event_device ced; |
44 | struct clocksource cs; | 43 | struct clocksource cs; |
45 | }; | 44 | }; |
46 | 45 | ||
47 | static DEFINE_SPINLOCK(sh_tmu_lock); | 46 | static DEFINE_SPINLOCK(sh_tmu_lock); |
48 | 47 | ||
49 | #define TSTR -1 /* shared register */ | 48 | #define TSTR -1 /* shared register */ |
50 | #define TCOR 0 /* channel register */ | 49 | #define TCOR 0 /* channel register */ |
51 | #define TCNT 1 /* channel register */ | 50 | #define TCNT 1 /* channel register */ |
52 | #define TCR 2 /* channel register */ | 51 | #define TCR 2 /* channel register */ |
53 | 52 | ||
54 | static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr) | 53 | static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr) |
55 | { | 54 | { |
56 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 55 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; |
57 | void __iomem *base = p->mapbase; | 56 | void __iomem *base = p->mapbase; |
58 | unsigned long offs; | 57 | unsigned long offs; |
59 | 58 | ||
60 | if (reg_nr == TSTR) | 59 | if (reg_nr == TSTR) |
61 | return ioread8(base - cfg->channel_offset); | 60 | return ioread8(base - cfg->channel_offset); |
62 | 61 | ||
63 | offs = reg_nr << 2; | 62 | offs = reg_nr << 2; |
64 | 63 | ||
65 | if (reg_nr == TCR) | 64 | if (reg_nr == TCR) |
66 | return ioread16(base + offs); | 65 | return ioread16(base + offs); |
67 | else | 66 | else |
68 | return ioread32(base + offs); | 67 | return ioread32(base + offs); |
69 | } | 68 | } |
70 | 69 | ||
71 | static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr, | 70 | static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr, |
72 | unsigned long value) | 71 | unsigned long value) |
73 | { | 72 | { |
74 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 73 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; |
75 | void __iomem *base = p->mapbase; | 74 | void __iomem *base = p->mapbase; |
76 | unsigned long offs; | 75 | unsigned long offs; |
77 | 76 | ||
78 | if (reg_nr == TSTR) { | 77 | if (reg_nr == TSTR) { |
79 | iowrite8(value, base - cfg->channel_offset); | 78 | iowrite8(value, base - cfg->channel_offset); |
80 | return; | 79 | return; |
81 | } | 80 | } |
82 | 81 | ||
83 | offs = reg_nr << 2; | 82 | offs = reg_nr << 2; |
84 | 83 | ||
85 | if (reg_nr == TCR) | 84 | if (reg_nr == TCR) |
86 | iowrite16(value, base + offs); | 85 | iowrite16(value, base + offs); |
87 | else | 86 | else |
88 | iowrite32(value, base + offs); | 87 | iowrite32(value, base + offs); |
89 | } | 88 | } |
90 | 89 | ||
91 | static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start) | 90 | static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start) |
92 | { | 91 | { |
93 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 92 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; |
94 | unsigned long flags, value; | 93 | unsigned long flags, value; |
95 | 94 | ||
96 | /* start stop register shared by multiple timer channels */ | 95 | /* start stop register shared by multiple timer channels */ |
97 | spin_lock_irqsave(&sh_tmu_lock, flags); | 96 | spin_lock_irqsave(&sh_tmu_lock, flags); |
98 | value = sh_tmu_read(p, TSTR); | 97 | value = sh_tmu_read(p, TSTR); |
99 | 98 | ||
100 | if (start) | 99 | if (start) |
101 | value |= 1 << cfg->timer_bit; | 100 | value |= 1 << cfg->timer_bit; |
102 | else | 101 | else |
103 | value &= ~(1 << cfg->timer_bit); | 102 | value &= ~(1 << cfg->timer_bit); |
104 | 103 | ||
105 | sh_tmu_write(p, TSTR, value); | 104 | sh_tmu_write(p, TSTR, value); |
106 | spin_unlock_irqrestore(&sh_tmu_lock, flags); | 105 | spin_unlock_irqrestore(&sh_tmu_lock, flags); |
107 | } | 106 | } |
108 | 107 | ||
109 | static int sh_tmu_enable(struct sh_tmu_priv *p) | 108 | static int sh_tmu_enable(struct sh_tmu_priv *p) |
110 | { | 109 | { |
111 | int ret; | 110 | int ret; |
112 | 111 | ||
113 | /* wake up device and enable clock */ | 112 | /* enable clock */ |
114 | pm_runtime_get_sync(&p->pdev->dev); | ||
115 | ret = clk_enable(p->clk); | 113 | ret = clk_enable(p->clk); |
116 | if (ret) { | 114 | if (ret) { |
117 | dev_err(&p->pdev->dev, "cannot enable clock\n"); | 115 | dev_err(&p->pdev->dev, "cannot enable clock\n"); |
118 | pm_runtime_put_sync(&p->pdev->dev); | ||
119 | return ret; | 116 | return ret; |
120 | } | 117 | } |
121 | 118 | ||
122 | /* make sure channel is disabled */ | 119 | /* make sure channel is disabled */ |
123 | sh_tmu_start_stop_ch(p, 0); | 120 | sh_tmu_start_stop_ch(p, 0); |
124 | 121 | ||
125 | /* maximum timeout */ | 122 | /* maximum timeout */ |
126 | sh_tmu_write(p, TCOR, 0xffffffff); | 123 | sh_tmu_write(p, TCOR, 0xffffffff); |
127 | sh_tmu_write(p, TCNT, 0xffffffff); | 124 | sh_tmu_write(p, TCNT, 0xffffffff); |
128 | 125 | ||
129 | /* configure channel to parent clock / 4, irq off */ | 126 | /* configure channel to parent clock / 4, irq off */ |
130 | p->rate = clk_get_rate(p->clk) / 4; | 127 | p->rate = clk_get_rate(p->clk) / 4; |
131 | sh_tmu_write(p, TCR, 0x0000); | 128 | sh_tmu_write(p, TCR, 0x0000); |
132 | 129 | ||
133 | /* enable channel */ | 130 | /* enable channel */ |
134 | sh_tmu_start_stop_ch(p, 1); | 131 | sh_tmu_start_stop_ch(p, 1); |
135 | 132 | ||
136 | return 0; | 133 | return 0; |
137 | } | 134 | } |
138 | 135 | ||
139 | static void sh_tmu_disable(struct sh_tmu_priv *p) | 136 | static void sh_tmu_disable(struct sh_tmu_priv *p) |
140 | { | 137 | { |
141 | /* disable channel */ | 138 | /* disable channel */ |
142 | sh_tmu_start_stop_ch(p, 0); | 139 | sh_tmu_start_stop_ch(p, 0); |
143 | 140 | ||
144 | /* disable interrupts in TMU block */ | 141 | /* disable interrupts in TMU block */ |
145 | sh_tmu_write(p, TCR, 0x0000); | 142 | sh_tmu_write(p, TCR, 0x0000); |
146 | 143 | ||
147 | /* stop clock and mark device as idle */ | 144 | /* stop clock */ |
148 | clk_disable(p->clk); | 145 | clk_disable(p->clk); |
149 | pm_runtime_put_sync(&p->pdev->dev); | ||
150 | } | 146 | } |
151 | 147 | ||
152 | static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, | 148 | static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, |
153 | int periodic) | 149 | int periodic) |
154 | { | 150 | { |
155 | /* stop timer */ | 151 | /* stop timer */ |
156 | sh_tmu_start_stop_ch(p, 0); | 152 | sh_tmu_start_stop_ch(p, 0); |
157 | 153 | ||
158 | /* acknowledge interrupt */ | 154 | /* acknowledge interrupt */ |
159 | sh_tmu_read(p, TCR); | 155 | sh_tmu_read(p, TCR); |
160 | 156 | ||
161 | /* enable interrupt */ | 157 | /* enable interrupt */ |
162 | sh_tmu_write(p, TCR, 0x0020); | 158 | sh_tmu_write(p, TCR, 0x0020); |
163 | 159 | ||
164 | /* reload delta value in case of periodic timer */ | 160 | /* reload delta value in case of periodic timer */ |
165 | if (periodic) | 161 | if (periodic) |
166 | sh_tmu_write(p, TCOR, delta); | 162 | sh_tmu_write(p, TCOR, delta); |
167 | else | 163 | else |
168 | sh_tmu_write(p, TCOR, 0xffffffff); | 164 | sh_tmu_write(p, TCOR, 0xffffffff); |
169 | 165 | ||
170 | sh_tmu_write(p, TCNT, delta); | 166 | sh_tmu_write(p, TCNT, delta); |
171 | 167 | ||
172 | /* start timer */ | 168 | /* start timer */ |
173 | sh_tmu_start_stop_ch(p, 1); | 169 | sh_tmu_start_stop_ch(p, 1); |
174 | } | 170 | } |
175 | 171 | ||
176 | static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) | 172 | static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) |
177 | { | 173 | { |
178 | struct sh_tmu_priv *p = dev_id; | 174 | struct sh_tmu_priv *p = dev_id; |
179 | 175 | ||
180 | /* disable or acknowledge interrupt */ | 176 | /* disable or acknowledge interrupt */ |
181 | if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) | 177 | if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) |
182 | sh_tmu_write(p, TCR, 0x0000); | 178 | sh_tmu_write(p, TCR, 0x0000); |
183 | else | 179 | else |
184 | sh_tmu_write(p, TCR, 0x0020); | 180 | sh_tmu_write(p, TCR, 0x0020); |
185 | 181 | ||
186 | /* notify clockevent layer */ | 182 | /* notify clockevent layer */ |
187 | p->ced.event_handler(&p->ced); | 183 | p->ced.event_handler(&p->ced); |
188 | return IRQ_HANDLED; | 184 | return IRQ_HANDLED; |
189 | } | 185 | } |
190 | 186 | ||
191 | static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs) | 187 | static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs) |
192 | { | 188 | { |
193 | return container_of(cs, struct sh_tmu_priv, cs); | 189 | return container_of(cs, struct sh_tmu_priv, cs); |
194 | } | 190 | } |
195 | 191 | ||
196 | static cycle_t sh_tmu_clocksource_read(struct clocksource *cs) | 192 | static cycle_t sh_tmu_clocksource_read(struct clocksource *cs) |
197 | { | 193 | { |
198 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); | 194 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); |
199 | 195 | ||
200 | return sh_tmu_read(p, TCNT) ^ 0xffffffff; | 196 | return sh_tmu_read(p, TCNT) ^ 0xffffffff; |
201 | } | 197 | } |
202 | 198 | ||
203 | static int sh_tmu_clocksource_enable(struct clocksource *cs) | 199 | static int sh_tmu_clocksource_enable(struct clocksource *cs) |
204 | { | 200 | { |
205 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); | 201 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); |
206 | int ret; | 202 | int ret; |
207 | 203 | ||
208 | ret = sh_tmu_enable(p); | 204 | ret = sh_tmu_enable(p); |
209 | if (!ret) | 205 | if (!ret) |
210 | __clocksource_updatefreq_hz(cs, p->rate); | 206 | __clocksource_updatefreq_hz(cs, p->rate); |
211 | return ret; | 207 | return ret; |
212 | } | 208 | } |
213 | 209 | ||
214 | static void sh_tmu_clocksource_disable(struct clocksource *cs) | 210 | static void sh_tmu_clocksource_disable(struct clocksource *cs) |
215 | { | 211 | { |
216 | sh_tmu_disable(cs_to_sh_tmu(cs)); | 212 | sh_tmu_disable(cs_to_sh_tmu(cs)); |
217 | } | 213 | } |
218 | 214 | ||
219 | static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, | 215 | static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, |
220 | char *name, unsigned long rating) | 216 | char *name, unsigned long rating) |
221 | { | 217 | { |
222 | struct clocksource *cs = &p->cs; | 218 | struct clocksource *cs = &p->cs; |
223 | 219 | ||
224 | cs->name = name; | 220 | cs->name = name; |
225 | cs->rating = rating; | 221 | cs->rating = rating; |
226 | cs->read = sh_tmu_clocksource_read; | 222 | cs->read = sh_tmu_clocksource_read; |
227 | cs->enable = sh_tmu_clocksource_enable; | 223 | cs->enable = sh_tmu_clocksource_enable; |
228 | cs->disable = sh_tmu_clocksource_disable; | 224 | cs->disable = sh_tmu_clocksource_disable; |
229 | cs->mask = CLOCKSOURCE_MASK(32); | 225 | cs->mask = CLOCKSOURCE_MASK(32); |
230 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; | 226 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; |
231 | 227 | ||
232 | dev_info(&p->pdev->dev, "used as clock source\n"); | 228 | dev_info(&p->pdev->dev, "used as clock source\n"); |
233 | 229 | ||
234 | /* Register with dummy 1 Hz value, gets updated in ->enable() */ | 230 | /* Register with dummy 1 Hz value, gets updated in ->enable() */ |
235 | clocksource_register_hz(cs, 1); | 231 | clocksource_register_hz(cs, 1); |
236 | return 0; | 232 | return 0; |
237 | } | 233 | } |
238 | 234 | ||
239 | static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced) | 235 | static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced) |
240 | { | 236 | { |
241 | return container_of(ced, struct sh_tmu_priv, ced); | 237 | return container_of(ced, struct sh_tmu_priv, ced); |
242 | } | 238 | } |
243 | 239 | ||
244 | static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic) | 240 | static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic) |
245 | { | 241 | { |
246 | struct clock_event_device *ced = &p->ced; | 242 | struct clock_event_device *ced = &p->ced; |
247 | 243 | ||
248 | sh_tmu_enable(p); | 244 | sh_tmu_enable(p); |
249 | 245 | ||
250 | /* TODO: calculate good shift from rate and counter bit width */ | 246 | /* TODO: calculate good shift from rate and counter bit width */ |
251 | 247 | ||
252 | ced->shift = 32; | 248 | ced->shift = 32; |
253 | ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift); | 249 | ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift); |
254 | ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced); | 250 | ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced); |
255 | ced->min_delta_ns = 5000; | 251 | ced->min_delta_ns = 5000; |
256 | 252 | ||
257 | if (periodic) { | 253 | if (periodic) { |
258 | p->periodic = (p->rate + HZ/2) / HZ; | 254 | p->periodic = (p->rate + HZ/2) / HZ; |
259 | sh_tmu_set_next(p, p->periodic, 1); | 255 | sh_tmu_set_next(p, p->periodic, 1); |
260 | } | 256 | } |
261 | } | 257 | } |
262 | 258 | ||
263 | static void sh_tmu_clock_event_mode(enum clock_event_mode mode, | 259 | static void sh_tmu_clock_event_mode(enum clock_event_mode mode, |
264 | struct clock_event_device *ced) | 260 | struct clock_event_device *ced) |
265 | { | 261 | { |
266 | struct sh_tmu_priv *p = ced_to_sh_tmu(ced); | 262 | struct sh_tmu_priv *p = ced_to_sh_tmu(ced); |
267 | int disabled = 0; | 263 | int disabled = 0; |
268 | 264 | ||
269 | /* deal with old setting first */ | 265 | /* deal with old setting first */ |
270 | switch (ced->mode) { | 266 | switch (ced->mode) { |
271 | case CLOCK_EVT_MODE_PERIODIC: | 267 | case CLOCK_EVT_MODE_PERIODIC: |
272 | case CLOCK_EVT_MODE_ONESHOT: | 268 | case CLOCK_EVT_MODE_ONESHOT: |
273 | sh_tmu_disable(p); | 269 | sh_tmu_disable(p); |
274 | disabled = 1; | 270 | disabled = 1; |
275 | break; | 271 | break; |
276 | default: | 272 | default: |
277 | break; | 273 | break; |
278 | } | 274 | } |
279 | 275 | ||
280 | switch (mode) { | 276 | switch (mode) { |
281 | case CLOCK_EVT_MODE_PERIODIC: | 277 | case CLOCK_EVT_MODE_PERIODIC: |
282 | dev_info(&p->pdev->dev, "used for periodic clock events\n"); | 278 | dev_info(&p->pdev->dev, "used for periodic clock events\n"); |
283 | sh_tmu_clock_event_start(p, 1); | 279 | sh_tmu_clock_event_start(p, 1); |
284 | break; | 280 | break; |
285 | case CLOCK_EVT_MODE_ONESHOT: | 281 | case CLOCK_EVT_MODE_ONESHOT: |
286 | dev_info(&p->pdev->dev, "used for oneshot clock events\n"); | 282 | dev_info(&p->pdev->dev, "used for oneshot clock events\n"); |
287 | sh_tmu_clock_event_start(p, 0); | 283 | sh_tmu_clock_event_start(p, 0); |
288 | break; | 284 | break; |
289 | case CLOCK_EVT_MODE_UNUSED: | 285 | case CLOCK_EVT_MODE_UNUSED: |
290 | if (!disabled) | 286 | if (!disabled) |
291 | sh_tmu_disable(p); | 287 | sh_tmu_disable(p); |
292 | break; | 288 | break; |
293 | case CLOCK_EVT_MODE_SHUTDOWN: | 289 | case CLOCK_EVT_MODE_SHUTDOWN: |
294 | default: | 290 | default: |
295 | break; | 291 | break; |
296 | } | 292 | } |
297 | } | 293 | } |
298 | 294 | ||
299 | static int sh_tmu_clock_event_next(unsigned long delta, | 295 | static int sh_tmu_clock_event_next(unsigned long delta, |
300 | struct clock_event_device *ced) | 296 | struct clock_event_device *ced) |
301 | { | 297 | { |
302 | struct sh_tmu_priv *p = ced_to_sh_tmu(ced); | 298 | struct sh_tmu_priv *p = ced_to_sh_tmu(ced); |
303 | 299 | ||
304 | BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); | 300 | BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); |
305 | 301 | ||
306 | /* program new delta value */ | 302 | /* program new delta value */ |
307 | sh_tmu_set_next(p, delta, 0); | 303 | sh_tmu_set_next(p, delta, 0); |
308 | return 0; | 304 | return 0; |
309 | } | 305 | } |
310 | 306 | ||
311 | static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, | 307 | static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, |
312 | char *name, unsigned long rating) | 308 | char *name, unsigned long rating) |
313 | { | 309 | { |
314 | struct clock_event_device *ced = &p->ced; | 310 | struct clock_event_device *ced = &p->ced; |
315 | int ret; | 311 | int ret; |
316 | 312 | ||
317 | memset(ced, 0, sizeof(*ced)); | 313 | memset(ced, 0, sizeof(*ced)); |
318 | 314 | ||
319 | ced->name = name; | 315 | ced->name = name; |
320 | ced->features = CLOCK_EVT_FEAT_PERIODIC; | 316 | ced->features = CLOCK_EVT_FEAT_PERIODIC; |
321 | ced->features |= CLOCK_EVT_FEAT_ONESHOT; | 317 | ced->features |= CLOCK_EVT_FEAT_ONESHOT; |
322 | ced->rating = rating; | 318 | ced->rating = rating; |
323 | ced->cpumask = cpumask_of(0); | 319 | ced->cpumask = cpumask_of(0); |
324 | ced->set_next_event = sh_tmu_clock_event_next; | 320 | ced->set_next_event = sh_tmu_clock_event_next; |
325 | ced->set_mode = sh_tmu_clock_event_mode; | 321 | ced->set_mode = sh_tmu_clock_event_mode; |
326 | 322 | ||
327 | dev_info(&p->pdev->dev, "used for clock events\n"); | 323 | dev_info(&p->pdev->dev, "used for clock events\n"); |
328 | clockevents_register_device(ced); | 324 | clockevents_register_device(ced); |
329 | 325 | ||
330 | ret = setup_irq(p->irqaction.irq, &p->irqaction); | 326 | ret = setup_irq(p->irqaction.irq, &p->irqaction); |
331 | if (ret) { | 327 | if (ret) { |
332 | dev_err(&p->pdev->dev, "failed to request irq %d\n", | 328 | dev_err(&p->pdev->dev, "failed to request irq %d\n", |
333 | p->irqaction.irq); | 329 | p->irqaction.irq); |
334 | return; | 330 | return; |
335 | } | 331 | } |
336 | } | 332 | } |
337 | 333 | ||
338 | static int sh_tmu_register(struct sh_tmu_priv *p, char *name, | 334 | static int sh_tmu_register(struct sh_tmu_priv *p, char *name, |
339 | unsigned long clockevent_rating, | 335 | unsigned long clockevent_rating, |
340 | unsigned long clocksource_rating) | 336 | unsigned long clocksource_rating) |
341 | { | 337 | { |
342 | if (clockevent_rating) | 338 | if (clockevent_rating) |
343 | sh_tmu_register_clockevent(p, name, clockevent_rating); | 339 | sh_tmu_register_clockevent(p, name, clockevent_rating); |
344 | else if (clocksource_rating) | 340 | else if (clocksource_rating) |
345 | sh_tmu_register_clocksource(p, name, clocksource_rating); | 341 | sh_tmu_register_clocksource(p, name, clocksource_rating); |
346 | 342 | ||
347 | return 0; | 343 | return 0; |
348 | } | 344 | } |
349 | 345 | ||
350 | static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) | 346 | static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) |
351 | { | 347 | { |
352 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 348 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
353 | struct resource *res; | 349 | struct resource *res; |
354 | int irq, ret; | 350 | int irq, ret; |
355 | ret = -ENXIO; | 351 | ret = -ENXIO; |
356 | 352 | ||
357 | memset(p, 0, sizeof(*p)); | 353 | memset(p, 0, sizeof(*p)); |
358 | p->pdev = pdev; | 354 | p->pdev = pdev; |
359 | 355 | ||
360 | if (!cfg) { | 356 | if (!cfg) { |
361 | dev_err(&p->pdev->dev, "missing platform data\n"); | 357 | dev_err(&p->pdev->dev, "missing platform data\n"); |
362 | goto err0; | 358 | goto err0; |
363 | } | 359 | } |
364 | 360 | ||
365 | platform_set_drvdata(pdev, p); | 361 | platform_set_drvdata(pdev, p); |
366 | 362 | ||
367 | res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); | 363 | res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); |
368 | if (!res) { | 364 | if (!res) { |
369 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | 365 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); |
370 | goto err0; | 366 | goto err0; |
371 | } | 367 | } |
372 | 368 | ||
373 | irq = platform_get_irq(p->pdev, 0); | 369 | irq = platform_get_irq(p->pdev, 0); |
374 | if (irq < 0) { | 370 | if (irq < 0) { |
375 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 371 | dev_err(&p->pdev->dev, "failed to get irq\n"); |
376 | goto err0; | 372 | goto err0; |
377 | } | 373 | } |
378 | 374 | ||
379 | /* map memory, let mapbase point to our channel */ | 375 | /* map memory, let mapbase point to our channel */ |
380 | p->mapbase = ioremap_nocache(res->start, resource_size(res)); | 376 | p->mapbase = ioremap_nocache(res->start, resource_size(res)); |
381 | if (p->mapbase == NULL) { | 377 | if (p->mapbase == NULL) { |
382 | dev_err(&p->pdev->dev, "failed to remap I/O memory\n"); | 378 | dev_err(&p->pdev->dev, "failed to remap I/O memory\n"); |
383 | goto err0; | 379 | goto err0; |
384 | } | 380 | } |
385 | 381 | ||
386 | /* setup data for setup_irq() (too early for request_irq()) */ | 382 | /* setup data for setup_irq() (too early for request_irq()) */ |
387 | p->irqaction.name = dev_name(&p->pdev->dev); | 383 | p->irqaction.name = dev_name(&p->pdev->dev); |
388 | p->irqaction.handler = sh_tmu_interrupt; | 384 | p->irqaction.handler = sh_tmu_interrupt; |
389 | p->irqaction.dev_id = p; | 385 | p->irqaction.dev_id = p; |
390 | p->irqaction.irq = irq; | 386 | p->irqaction.irq = irq; |
391 | p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \ | 387 | p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \ |
392 | IRQF_IRQPOLL | IRQF_NOBALANCING; | 388 | IRQF_IRQPOLL | IRQF_NOBALANCING; |
393 | 389 | ||
394 | /* get hold of clock */ | 390 | /* get hold of clock */ |
395 | p->clk = clk_get(&p->pdev->dev, "tmu_fck"); | 391 | p->clk = clk_get(&p->pdev->dev, "tmu_fck"); |
396 | if (IS_ERR(p->clk)) { | 392 | if (IS_ERR(p->clk)) { |
397 | dev_err(&p->pdev->dev, "cannot get clock\n"); | 393 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
398 | ret = PTR_ERR(p->clk); | 394 | ret = PTR_ERR(p->clk); |
399 | goto err1; | 395 | goto err1; |
400 | } | 396 | } |
401 | 397 | ||
402 | return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev), | 398 | return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev), |
403 | cfg->clockevent_rating, | 399 | cfg->clockevent_rating, |
404 | cfg->clocksource_rating); | 400 | cfg->clocksource_rating); |
405 | err1: | 401 | err1: |
406 | iounmap(p->mapbase); | 402 | iounmap(p->mapbase); |
407 | err0: | 403 | err0: |
408 | return ret; | 404 | return ret; |
409 | } | 405 | } |
410 | 406 | ||
411 | static int __devinit sh_tmu_probe(struct platform_device *pdev) | 407 | static int __devinit sh_tmu_probe(struct platform_device *pdev) |
412 | { | 408 | { |
413 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); | 409 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); |
414 | int ret; | 410 | int ret; |
415 | 411 | ||
416 | if (p) { | 412 | if (p) { |
417 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 413 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
418 | pm_runtime_enable(&pdev->dev); | ||
419 | return 0; | 414 | return 0; |
420 | } | 415 | } |
421 | 416 | ||
422 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 417 | p = kmalloc(sizeof(*p), GFP_KERNEL); |
423 | if (p == NULL) { | 418 | if (p == NULL) { |
424 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | 419 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
425 | return -ENOMEM; | 420 | return -ENOMEM; |
426 | } | 421 | } |
427 | 422 | ||
428 | ret = sh_tmu_setup(p, pdev); | 423 | ret = sh_tmu_setup(p, pdev); |
429 | if (ret) { | 424 | if (ret) { |
430 | kfree(p); | 425 | kfree(p); |
431 | platform_set_drvdata(pdev, NULL); | 426 | platform_set_drvdata(pdev, NULL); |
432 | } | 427 | } |
433 | |||
434 | if (!is_early_platform_device(pdev)) | ||
435 | pm_runtime_enable(&pdev->dev); | ||
436 | return ret; | 428 | return ret; |
437 | } | 429 | } |
438 | 430 | ||
439 | static int __devexit sh_tmu_remove(struct platform_device *pdev) | 431 | static int __devexit sh_tmu_remove(struct platform_device *pdev) |
440 | { | 432 | { |
441 | return -EBUSY; /* cannot unregister clockevent and clocksource */ | 433 | return -EBUSY; /* cannot unregister clockevent and clocksource */ |
442 | } | 434 | } |
443 | 435 | ||
444 | static struct platform_driver sh_tmu_device_driver = { | 436 | static struct platform_driver sh_tmu_device_driver = { |
445 | .probe = sh_tmu_probe, | 437 | .probe = sh_tmu_probe, |
446 | .remove = __devexit_p(sh_tmu_remove), | 438 | .remove = __devexit_p(sh_tmu_remove), |
447 | .driver = { | 439 | .driver = { |
448 | .name = "sh_tmu", | 440 | .name = "sh_tmu", |
449 | } | 441 | } |
450 | }; | 442 | }; |
451 | 443 | ||
452 | static int __init sh_tmu_init(void) | 444 | static int __init sh_tmu_init(void) |
453 | { | 445 | { |
454 | return platform_driver_register(&sh_tmu_device_driver); | 446 | return platform_driver_register(&sh_tmu_device_driver); |
455 | } | 447 | } |
456 | 448 | ||
457 | static void __exit sh_tmu_exit(void) | 449 | static void __exit sh_tmu_exit(void) |
458 | { | 450 | { |
459 | platform_driver_unregister(&sh_tmu_device_driver); | 451 | platform_driver_unregister(&sh_tmu_device_driver); |
460 | } | 452 | } |
461 | 453 | ||
462 | early_platform_init("earlytimer", &sh_tmu_device_driver); | 454 | early_platform_init("earlytimer", &sh_tmu_device_driver); |
463 | module_init(sh_tmu_init); | 455 | module_init(sh_tmu_init); |
464 | module_exit(sh_tmu_exit); | 456 | module_exit(sh_tmu_exit); |
465 | 457 | ||
466 | MODULE_AUTHOR("Magnus Damm"); | 458 | MODULE_AUTHOR("Magnus Damm"); |
467 | MODULE_DESCRIPTION("SuperH TMU Timer Driver"); | 459 | MODULE_DESCRIPTION("SuperH TMU Timer Driver"); |
468 | MODULE_LICENSE("GPL v2"); | 460 | MODULE_LICENSE("GPL v2"); |
469 | 461 |