Merge tag 'irqchip-core-3.18' of git://git.infradead.org/users/jcooper/linux into...
[deliverable/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 }
This page took 0.054924 seconds and 5 git commands to generate.