2 * linux/arch/h8300/kernel/cpu/timer/timer8.c
4 * Yoshinori Sato <ysato@users.sourcefoge.jp>
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/kernel.h>
13 #include <linux/interrupt.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 #include <linux/clockchips.h>
18 #include <linux/module.h>
19 #include <linux/clk.h>
31 #define FLAG_REPROGRAM (1 << 0)
32 #define FLAG_SKIPEVENT (1 << 1)
33 #define FLAG_IRQCONTEXT (1 << 2)
34 #define FLAG_STARTED (1 << 3)
43 struct platform_device
*pdev
;
44 struct clock_event_device ced
;
45 struct irqaction irqaction
;
46 unsigned long mapbase
;
54 static unsigned long timer8_get_counter(struct timer8_priv
*p
)
56 unsigned long v1
, v2
, v3
;
59 o1
= ctrl_inb(p
->mapbase
+ _8TCSR
) & 0x20;
61 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
64 v1
= ctrl_inw(p
->mapbase
+ _8TCNT
);
65 v2
= ctrl_inw(p
->mapbase
+ _8TCNT
);
66 v3
= ctrl_inw(p
->mapbase
+ _8TCNT
);
67 o1
= ctrl_inb(p
->mapbase
+ _8TCSR
) & 0x20;
68 } while (unlikely((o1
!= o2
) || (v1
> v2
&& v1
< v3
)
69 || (v2
> v3
&& v2
< v1
) || (v3
> v1
&& v3
< v2
)));
75 static irqreturn_t
timer8_interrupt(int irq
, void *dev_id
)
77 struct timer8_priv
*p
= dev_id
;
79 ctrl_outb(ctrl_inb(p
->mapbase
+ _8TCSR
) & ~0x40,
81 p
->flags
|= FLAG_IRQCONTEXT
;
82 ctrl_outw(p
->tcora
, p
->mapbase
+ TCORA
);
83 if (!(p
->flags
& FLAG_SKIPEVENT
)) {
84 if (clockevent_state_oneshot(&p
->ced
))
85 ctrl_outw(0x0000, p
->mapbase
+ _8TCR
);
86 p
->ced
.event_handler(&p
->ced
);
88 p
->flags
&= ~(FLAG_SKIPEVENT
| FLAG_IRQCONTEXT
);
93 static void timer8_set_next(struct timer8_priv
*p
, unsigned long delta
)
98 raw_spin_lock_irqsave(&p
->lock
, flags
);
100 dev_warn(&p
->pdev
->dev
, "delta out of range\n");
101 now
= timer8_get_counter(p
);
103 ctrl_outb(ctrl_inb(p
->mapbase
+ _8TCR
) | 0x40, p
->mapbase
+ _8TCR
);
105 ctrl_outw(delta
, p
->mapbase
+ TCORA
);
107 ctrl_outw(now
+ 1, p
->mapbase
+ TCORA
);
109 raw_spin_unlock_irqrestore(&p
->lock
, flags
);
112 static int timer8_enable(struct timer8_priv
*p
)
114 p
->rate
= clk_get_rate(p
->pclk
) / 64;
115 ctrl_outw(0xffff, p
->mapbase
+ TCORA
);
116 ctrl_outw(0x0000, p
->mapbase
+ _8TCNT
);
117 ctrl_outw(0x0c02, p
->mapbase
+ _8TCR
);
122 static int timer8_start(struct timer8_priv
*p
)
127 raw_spin_lock_irqsave(&p
->lock
, flags
);
129 if (!(p
->flags
& FLAG_STARTED
))
130 ret
= timer8_enable(p
);
134 p
->flags
|= FLAG_STARTED
;
137 raw_spin_unlock_irqrestore(&p
->lock
, flags
);
142 static void timer8_stop(struct timer8_priv
*p
)
146 raw_spin_lock_irqsave(&p
->lock
, flags
);
148 ctrl_outw(0x0000, p
->mapbase
+ _8TCR
);
150 raw_spin_unlock_irqrestore(&p
->lock
, flags
);
153 static inline struct timer8_priv
*ced_to_priv(struct clock_event_device
*ced
)
155 return container_of(ced
, struct timer8_priv
, ced
);
158 static void timer8_clock_event_start(struct timer8_priv
*p
, int periodic
)
160 struct clock_event_device
*ced
= &p
->ced
;
165 ced
->mult
= div_sc(p
->rate
, NSEC_PER_SEC
, ced
->shift
);
166 ced
->max_delta_ns
= clockevent_delta2ns(0xffff, ced
);
167 ced
->min_delta_ns
= clockevent_delta2ns(0x0001, ced
);
169 timer8_set_next(p
, periodic
?(p
->rate
+ HZ
/2) / HZ
:0x10000);
172 static int timer8_clock_event_shutdown(struct clock_event_device
*ced
)
174 timer8_stop(ced_to_priv(ced
));
178 static int timer8_clock_event_periodic(struct clock_event_device
*ced
)
180 struct timer8_priv
*p
= ced_to_priv(ced
);
182 dev_info(&p
->pdev
->dev
, "used for periodic clock events\n");
184 timer8_clock_event_start(p
, PERIODIC
);
189 static int timer8_clock_event_oneshot(struct clock_event_device
*ced
)
191 struct timer8_priv
*p
= ced_to_priv(ced
);
193 dev_info(&p
->pdev
->dev
, "used for oneshot clock events\n");
195 timer8_clock_event_start(p
, ONESHOT
);
200 static int timer8_clock_event_next(unsigned long delta
,
201 struct clock_event_device
*ced
)
203 struct timer8_priv
*p
= ced_to_priv(ced
);
205 BUG_ON(!clockevent_state_oneshot(ced
));
206 timer8_set_next(p
, delta
- 1);
211 static int timer8_setup(struct timer8_priv
*p
,
212 struct platform_device
*pdev
)
214 struct resource
*res
;
220 res
= platform_get_resource(p
->pdev
, IORESOURCE_MEM
, 0);
222 dev_err(&p
->pdev
->dev
, "failed to get I/O memory\n");
226 irq
= platform_get_irq(p
->pdev
, 0);
228 dev_err(&p
->pdev
->dev
, "failed to get irq\n");
232 p
->mapbase
= res
->start
;
234 p
->irqaction
.name
= dev_name(&p
->pdev
->dev
);
235 p
->irqaction
.handler
= timer8_interrupt
;
236 p
->irqaction
.dev_id
= p
;
237 p
->irqaction
.flags
= IRQF_TIMER
;
239 p
->pclk
= clk_get(&p
->pdev
->dev
, "fck");
240 if (IS_ERR(p
->pclk
)) {
241 dev_err(&p
->pdev
->dev
, "can't get clk\n");
242 return PTR_ERR(p
->pclk
);
245 p
->ced
.name
= pdev
->name
;
246 p
->ced
.features
= CLOCK_EVT_FEAT_PERIODIC
|
247 CLOCK_EVT_FEAT_ONESHOT
;
249 p
->ced
.cpumask
= cpumask_of(0);
250 p
->ced
.set_next_event
= timer8_clock_event_next
;
251 p
->ced
.set_state_shutdown
= timer8_clock_event_shutdown
;
252 p
->ced
.set_state_periodic
= timer8_clock_event_periodic
;
253 p
->ced
.set_state_oneshot
= timer8_clock_event_oneshot
;
255 ret
= setup_irq(irq
, &p
->irqaction
);
257 dev_err(&p
->pdev
->dev
,
258 "failed to request irq %d\n", irq
);
261 clockevents_register_device(&p
->ced
);
262 platform_set_drvdata(pdev
, p
);
267 static int timer8_probe(struct platform_device
*pdev
)
269 struct timer8_priv
*p
= platform_get_drvdata(pdev
);
272 dev_info(&pdev
->dev
, "kept as earlytimer\n");
276 p
= devm_kzalloc(&pdev
->dev
, sizeof(*p
), GFP_KERNEL
);
280 return timer8_setup(p
, pdev
);
283 static int timer8_remove(struct platform_device
*pdev
)
288 static const struct of_device_id timer8_of_table
[] __maybe_unused
= {
289 { .compatible
= "renesas,8bit-timer" },
293 MODULE_DEVICE_TABLE(of
, timer8_of_table
);
294 static struct platform_driver timer8_driver
= {
295 .probe
= timer8_probe
,
296 .remove
= timer8_remove
,
298 .name
= "h8300-8timer",
299 .of_match_table
= of_match_ptr(timer8_of_table
),
303 static int __init
timer8_init(void)
305 return platform_driver_register(&timer8_driver
);
308 static void __exit
timer8_exit(void)
310 platform_driver_unregister(&timer8_driver
);
313 subsys_initcall(timer8_init
);
314 module_exit(timer8_exit
);
315 MODULE_AUTHOR("Yoshinori Sato");
316 MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
317 MODULE_LICENSE("GPL v2");