• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@cam.org>
8  *	Rewritten: big cleanup, much simpler, better HZ accuracy.
9  *
10  */
11 #include <linux/init.h>
12 #include <linux/errno.h>
13 #include <linux/interrupt.h>
14 #include <linux/irq.h>
15 #include <linux/timex.h>
16 #include <linux/clockchips.h>
17 
18 #include <asm/mach/time.h>
19 #include <mach/hardware.h>
20 
21 #define MIN_OSCR_DELTA 2
22 
sa1100_ost0_interrupt(int irq,void * dev_id)23 static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id)
24 {
25 	struct clock_event_device *c = dev_id;
26 
27 	/* Disarm the compare/match, signal the event. */
28 	OIER &= ~OIER_E0;
29 	OSSR = OSSR_M0;
30 	c->event_handler(c);
31 
32 	return IRQ_HANDLED;
33 }
34 
35 static int
sa1100_osmr0_set_next_event(unsigned long delta,struct clock_event_device * c)36 sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
37 {
38 	unsigned long flags, next, oscr;
39 
40 	raw_local_irq_save(flags);
41 	OIER |= OIER_E0;
42 	next = OSCR + delta;
43 	OSMR0 = next;
44 	oscr = OSCR;
45 	raw_local_irq_restore(flags);
46 
47 	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
48 }
49 
50 static void
sa1100_osmr0_set_mode(enum clock_event_mode mode,struct clock_event_device * c)51 sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
52 {
53 	unsigned long flags;
54 
55 	switch (mode) {
56 	case CLOCK_EVT_MODE_ONESHOT:
57 	case CLOCK_EVT_MODE_UNUSED:
58 	case CLOCK_EVT_MODE_SHUTDOWN:
59 		raw_local_irq_save(flags);
60 		OIER &= ~OIER_E0;
61 		OSSR = OSSR_M0;
62 		raw_local_irq_restore(flags);
63 		break;
64 
65 	case CLOCK_EVT_MODE_RESUME:
66 	case CLOCK_EVT_MODE_PERIODIC:
67 		break;
68 	}
69 }
70 
71 static struct clock_event_device ckevt_sa1100_osmr0 = {
72 	.name		= "osmr0",
73 	.features	= CLOCK_EVT_FEAT_ONESHOT,
74 	.shift		= 32,
75 	.rating		= 200,
76 	.set_next_event	= sa1100_osmr0_set_next_event,
77 	.set_mode	= sa1100_osmr0_set_mode,
78 };
79 
sa1100_read_oscr(void)80 static cycle_t sa1100_read_oscr(void)
81 {
82 	return OSCR;
83 }
84 
85 static struct clocksource cksrc_sa1100_oscr = {
86 	.name		= "oscr",
87 	.rating		= 200,
88 	.read		= sa1100_read_oscr,
89 	.mask		= CLOCKSOURCE_MASK(32),
90 	.shift		= 20,
91 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
92 };
93 
94 static struct irqaction sa1100_timer_irq = {
95 	.name		= "ost0",
96 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
97 	.handler	= sa1100_ost0_interrupt,
98 	.dev_id		= &ckevt_sa1100_osmr0,
99 };
100 
sa1100_timer_init(void)101 static void __init sa1100_timer_init(void)
102 {
103 	OIER = 0;		/* disable any timer interrupts */
104 	OSSR = 0xf;		/* clear status on all timers */
105 
106 	ckevt_sa1100_osmr0.mult =
107 		div_sc(3686400, NSEC_PER_SEC, ckevt_sa1100_osmr0.shift);
108 	ckevt_sa1100_osmr0.max_delta_ns =
109 		clockevent_delta2ns(0x7fffffff, &ckevt_sa1100_osmr0);
110 	ckevt_sa1100_osmr0.min_delta_ns =
111 		clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_sa1100_osmr0) + 1;
112 	ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
113 
114 	cksrc_sa1100_oscr.mult =
115 		clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_sa1100_oscr.shift);
116 
117 	setup_irq(IRQ_OST0, &sa1100_timer_irq);
118 
119 	clocksource_register(&cksrc_sa1100_oscr);
120 	clockevents_register_device(&ckevt_sa1100_osmr0);
121 }
122 
123 #ifdef CONFIG_PM
124 unsigned long osmr[4], oier;
125 
sa1100_timer_suspend(void)126 static void sa1100_timer_suspend(void)
127 {
128 	osmr[0] = OSMR0;
129 	osmr[1] = OSMR1;
130 	osmr[2] = OSMR2;
131 	osmr[3] = OSMR3;
132 	oier = OIER;
133 }
134 
sa1100_timer_resume(void)135 static void sa1100_timer_resume(void)
136 {
137 	OSSR = 0x0f;
138 	OSMR0 = osmr[0];
139 	OSMR1 = osmr[1];
140 	OSMR2 = osmr[2];
141 	OSMR3 = osmr[3];
142 	OIER = oier;
143 
144 	/*
145 	 * OSMR0 is the system timer: make sure OSCR is sufficiently behind
146 	 */
147 	OSCR = OSMR0 - LATCH;
148 }
149 #else
150 #define sa1100_timer_suspend NULL
151 #define sa1100_timer_resume NULL
152 #endif
153 
154 struct sys_timer sa1100_timer = {
155 	.init		= sa1100_timer_init,
156 	.suspend	= sa1100_timer_suspend,
157 	.resume		= sa1100_timer_resume,
158 };
159