| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/arch/arm/mach-sa1100/time.c | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 1998 Deborah Wallach. | 
| Kristoffer Ericson | 9398253 | 2008-11-26 20:58:43 +0100 | [diff] [blame] | 5 |  * Twiddles  (C) 1999 Hugo Fiennes <hugo@empeg.com> | 
 | 6 |  * | 
| Nicolas Pitre | 2f82af0 | 2009-09-14 03:25:28 -0400 | [diff] [blame] | 7 |  * 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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> | 
| Thomas Gleixner | 119c641 | 2006-07-01 22:32:38 +0100 | [diff] [blame] | 14 | #include <linux/irq.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/timex.h> | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 16 | #include <linux/clockchips.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 |  | 
 | 18 | #include <asm/mach/time.h> | 
| Russell King | 5094b92 | 2010-12-15 21:49:06 +0000 | [diff] [blame] | 19 | #include <asm/sched_clock.h> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 20 | #include <mach/hardware.h> | 
| Rob Herring | f314f33 | 2012-02-24 00:06:51 +0100 | [diff] [blame] | 21 | #include <mach/irqs.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 |  | 
| Linus Walleij | ef3a0bf | 2012-01-04 11:42:19 +0100 | [diff] [blame] | 23 | static u32 notrace sa1100_read_sched_clock(void) | 
| Russell King | 5094b92 | 2010-12-15 21:49:06 +0000 | [diff] [blame] | 24 | { | 
| Marc Zyngier | 2f0778af | 2011-12-15 12:19:23 +0100 | [diff] [blame] | 25 | 	return OSCR; | 
| Russell King | 5094b92 | 2010-12-15 21:49:06 +0000 | [diff] [blame] | 26 | } | 
 | 27 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 28 | #define MIN_OSCR_DELTA 2 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 30 | static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | { | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 32 | 	struct clock_event_device *c = dev_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 34 | 	/* Disarm the compare/match, signal the event. */ | 
 | 35 | 	OIER &= ~OIER_E0; | 
 | 36 | 	OSSR = OSSR_M0; | 
 | 37 | 	c->event_handler(c); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | 	return IRQ_HANDLED; | 
 | 40 | } | 
 | 41 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 42 | static int | 
 | 43 | sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c) | 
 | 44 | { | 
| Uwe Kleine-König | a602f0f | 2009-12-17 12:43:29 +0100 | [diff] [blame] | 45 | 	unsigned long next, oscr; | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 46 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 47 | 	OIER |= OIER_E0; | 
 | 48 | 	next = OSCR + delta; | 
 | 49 | 	OSMR0 = next; | 
 | 50 | 	oscr = OSCR; | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 51 |  | 
 | 52 | 	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; | 
 | 53 | } | 
 | 54 |  | 
 | 55 | static void | 
 | 56 | sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c) | 
 | 57 | { | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 58 | 	switch (mode) { | 
 | 59 | 	case CLOCK_EVT_MODE_ONESHOT: | 
 | 60 | 	case CLOCK_EVT_MODE_UNUSED: | 
 | 61 | 	case CLOCK_EVT_MODE_SHUTDOWN: | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 62 | 		OIER &= ~OIER_E0; | 
 | 63 | 		OSSR = OSSR_M0; | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 64 | 		break; | 
 | 65 |  | 
 | 66 | 	case CLOCK_EVT_MODE_RESUME: | 
 | 67 | 	case CLOCK_EVT_MODE_PERIODIC: | 
 | 68 | 		break; | 
 | 69 | 	} | 
 | 70 | } | 
 | 71 |  | 
 | 72 | static struct clock_event_device ckevt_sa1100_osmr0 = { | 
 | 73 | 	.name		= "osmr0", | 
 | 74 | 	.features	= CLOCK_EVT_FEAT_ONESHOT, | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 75 | 	.rating		= 200, | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 76 | 	.set_next_event	= sa1100_osmr0_set_next_event, | 
 | 77 | 	.set_mode	= sa1100_osmr0_set_mode, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | }; | 
 | 79 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 80 | static struct irqaction sa1100_timer_irq = { | 
 | 81 | 	.name		= "ost0", | 
 | 82 | 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 
 | 83 | 	.handler	= sa1100_ost0_interrupt, | 
 | 84 | 	.dev_id		= &ckevt_sa1100_osmr0, | 
 | 85 | }; | 
 | 86 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | static void __init sa1100_timer_init(void) | 
 | 88 | { | 
| Russell King | 1ba4c3c | 2011-05-08 16:14:40 +0100 | [diff] [blame] | 89 | 	OIER = 0; | 
 | 90 | 	OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 91 |  | 
| Marc Zyngier | 2f0778af | 2011-12-15 12:19:23 +0100 | [diff] [blame] | 92 | 	setup_sched_clock(sa1100_read_sched_clock, 32, 3686400); | 
| Russell King | 5094b92 | 2010-12-15 21:49:06 +0000 | [diff] [blame] | 93 |  | 
| Russell King | 1ba4c3c | 2011-05-08 16:14:40 +0100 | [diff] [blame] | 94 | 	clockevents_calc_mult_shift(&ckevt_sa1100_osmr0, 3686400, 4); | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 95 | 	ckevt_sa1100_osmr0.max_delta_ns = | 
 | 96 | 		clockevent_delta2ns(0x7fffffff, &ckevt_sa1100_osmr0); | 
 | 97 | 	ckevt_sa1100_osmr0.min_delta_ns = | 
 | 98 | 		clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_sa1100_osmr0) + 1; | 
| Rusty Russell | 320ab2b | 2008-12-13 21:20:26 +1030 | [diff] [blame] | 99 | 	ckevt_sa1100_osmr0.cpumask = cpumask_of(0); | 
| Russell King | d142b6e | 2007-11-12 21:55:12 +0000 | [diff] [blame] | 100 |  | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 101 | 	setup_irq(IRQ_OST0, &sa1100_timer_irq); | 
 | 102 |  | 
| Russell King | 234b6ce | 2011-05-08 14:09:47 +0100 | [diff] [blame] | 103 | 	clocksource_mmio_init(&OSCR, "oscr", CLOCK_TICK_RATE, 200, 32, | 
 | 104 | 		clocksource_mmio_readl_up); | 
| Russell King | 3e238be | 2008-04-14 23:03:10 +0100 | [diff] [blame] | 105 | 	clockevents_register_device(&ckevt_sa1100_osmr0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | } | 
 | 107 |  | 
 | 108 | #ifdef CONFIG_PM | 
 | 109 | unsigned long osmr[4], oier; | 
 | 110 |  | 
 | 111 | static void sa1100_timer_suspend(void) | 
 | 112 | { | 
 | 113 | 	osmr[0] = OSMR0; | 
 | 114 | 	osmr[1] = OSMR1; | 
 | 115 | 	osmr[2] = OSMR2; | 
 | 116 | 	osmr[3] = OSMR3; | 
 | 117 | 	oier = OIER; | 
 | 118 | } | 
 | 119 |  | 
 | 120 | static void sa1100_timer_resume(void) | 
 | 121 | { | 
 | 122 | 	OSSR = 0x0f; | 
 | 123 | 	OSMR0 = osmr[0]; | 
 | 124 | 	OSMR1 = osmr[1]; | 
 | 125 | 	OSMR2 = osmr[2]; | 
 | 126 | 	OSMR3 = osmr[3]; | 
 | 127 | 	OIER = oier; | 
 | 128 |  | 
 | 129 | 	/* | 
 | 130 | 	 * OSMR0 is the system timer: make sure OSCR is sufficiently behind | 
 | 131 | 	 */ | 
 | 132 | 	OSCR = OSMR0 - LATCH; | 
 | 133 | } | 
 | 134 | #else | 
 | 135 | #define sa1100_timer_suspend NULL | 
 | 136 | #define sa1100_timer_resume NULL | 
 | 137 | #endif | 
 | 138 |  | 
 | 139 | struct sys_timer sa1100_timer = { | 
 | 140 | 	.init		= sa1100_timer_init, | 
 | 141 | 	.suspend	= sa1100_timer_suspend, | 
 | 142 | 	.resume		= sa1100_timer_resume, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | }; |