Merge branch 'async-scsi-resume' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / arch / arm / mach-sa1100 / time.c
1 /*
2  * linux/arch/arm/mach-sa1100/time.c
3  *
4  * Copyright (C) 1998 Deborah Wallach.
5  * Twiddles  (C) 1999 Hugo Fiennes <hugo@empeg.com>
6  *
7  * 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net>
8  *      Rewritten: big cleanup, much simpler, better HZ accuracy.
9  *
10  */
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/timex.h>
17 #include <linux/clockchips.h>
18 #include <linux/sched_clock.h>
19
20 #include <asm/mach/time.h>
21 #include <mach/hardware.h>
22 #include <mach/irqs.h>
23
24 #define SA1100_CLOCK_FREQ 3686400
25 #define SA1100_LATCH DIV_ROUND_CLOSEST(SA1100_CLOCK_FREQ, HZ)
26
27 static u64 notrace sa1100_read_sched_clock(void)
28 {
29         return readl_relaxed(OSCR);
30 }
31
32 #define MIN_OSCR_DELTA 2
33
34 static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id)
35 {
36         struct clock_event_device *c = dev_id;
37
38         /* Disarm the compare/match, signal the event. */
39         writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
40         writel_relaxed(OSSR_M0, OSSR);
41         c->event_handler(c);
42
43         return IRQ_HANDLED;
44 }
45
46 static int
47 sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
48 {
49         unsigned long next, oscr;
50
51         writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
52         next = readl_relaxed(OSCR) + delta;
53         writel_relaxed(next, OSMR0);
54         oscr = readl_relaxed(OSCR);
55
56         return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
57 }
58
59 static void
60 sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
61 {
62         switch (mode) {
63         case CLOCK_EVT_MODE_ONESHOT:
64         case CLOCK_EVT_MODE_UNUSED:
65         case CLOCK_EVT_MODE_SHUTDOWN:
66                 writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
67                 writel_relaxed(OSSR_M0, OSSR);
68                 break;
69
70         case CLOCK_EVT_MODE_RESUME:
71         case CLOCK_EVT_MODE_PERIODIC:
72                 break;
73         }
74 }
75
76 #ifdef CONFIG_PM
77 unsigned long osmr[4], oier;
78
79 static void sa1100_timer_suspend(struct clock_event_device *cedev)
80 {
81         osmr[0] = readl_relaxed(OSMR0);
82         osmr[1] = readl_relaxed(OSMR1);
83         osmr[2] = readl_relaxed(OSMR2);
84         osmr[3] = readl_relaxed(OSMR3);
85         oier = readl_relaxed(OIER);
86 }
87
88 static void sa1100_timer_resume(struct clock_event_device *cedev)
89 {
90         writel_relaxed(0x0f, OSSR);
91         writel_relaxed(osmr[0], OSMR0);
92         writel_relaxed(osmr[1], OSMR1);
93         writel_relaxed(osmr[2], OSMR2);
94         writel_relaxed(osmr[3], OSMR3);
95         writel_relaxed(oier, OIER);
96
97         /*
98          * OSMR0 is the system timer: make sure OSCR is sufficiently behind
99          */
100         writel_relaxed(OSMR0 - SA1100_LATCH, OSCR);
101 }
102 #else
103 #define sa1100_timer_suspend NULL
104 #define sa1100_timer_resume NULL
105 #endif
106
107 static struct clock_event_device ckevt_sa1100_osmr0 = {
108         .name           = "osmr0",
109         .features       = CLOCK_EVT_FEAT_ONESHOT,
110         .rating         = 200,
111         .set_next_event = sa1100_osmr0_set_next_event,
112         .set_mode       = sa1100_osmr0_set_mode,
113         .suspend        = sa1100_timer_suspend,
114         .resume         = sa1100_timer_resume,
115 };
116
117 static struct irqaction sa1100_timer_irq = {
118         .name           = "ost0",
119         .flags          = IRQF_TIMER | IRQF_IRQPOLL,
120         .handler        = sa1100_ost0_interrupt,
121         .dev_id         = &ckevt_sa1100_osmr0,
122 };
123
124 void __init sa1100_timer_init(void)
125 {
126         writel_relaxed(0, OIER);
127         writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
128
129         sched_clock_register(sa1100_read_sched_clock, 32, 3686400);
130
131         ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
132
133         setup_irq(IRQ_OST0, &sa1100_timer_irq);
134
135         clocksource_mmio_init(OSCR, "oscr", SA1100_CLOCK_FREQ, 200, 32,
136                 clocksource_mmio_readl_up);
137         clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400,
138                                         MIN_OSCR_DELTA * 2, 0x7fffffff);
139 }