blob: b503049d6d2657f6147b0bc82929426e2fe9f463 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/arm/mach-pxa/time.c
3 *
Bill Gatliff7bbb18c2007-07-21 03:39:36 +01004 * PXA clocksource, clockevents, and OST interrupt handlers.
5 * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
6 *
7 * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
8 * by MontaVista Software, Inc. (Nico, your code rocks!)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/interrupt.h>
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010018#include <linux/clockchips.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Nicolas Pitre6c3a1582007-08-17 16:55:22 +010020#include <asm/div64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/mach/irq.h>
22#include <asm/mach/time.h>
Russell King7ce83012010-12-15 21:48:15 +000023#include <asm/sched_clock.h>
Eric Miao5bf3df32009-01-20 11:04:16 +080024#include <mach/regs-ost.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Nicolas Pitre6c3a1582007-08-17 16:55:22 +010026/*
27 * This is PXA's sched_clock implementation. This has a resolution
28 * of at least 308 ns and a maximum value of 208 days.
29 *
30 * The return value is guaranteed to be monotonic in that range as
31 * long as there is always less than 582 seconds between successive
32 * calls to sched_clock() which should always be the case in practice.
33 */
Nicolas Pitre6c3a1582007-08-17 16:55:22 +010034
Marc Zyngier2f0778af2011-12-15 12:19:23 +010035static u32 notrace pxa_read_sched_clock(void)
Nicolas Pitre6c3a1582007-08-17 16:55:22 +010036{
Marc Zyngier2f0778af2011-12-15 12:19:23 +010037 return OSCR;
Nicolas Pitre6c3a1582007-08-17 16:55:22 +010038}
39
40
Russell Kinga88264c2007-11-12 22:45:16 +000041#define MIN_OSCR_DELTA 16
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043static irqreturn_t
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010044pxa_ost0_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010046 struct clock_event_device *c = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Russell Kinga88264c2007-11-12 22:45:16 +000048 /* Disarm the compare/match, signal the event. */
49 OIER &= ~OIER_E0;
50 OSSR = OSSR_M0;
51 c->event_handler(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53 return IRQ_HANDLED;
54}
55
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010056static int
57pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
58{
Uwe Kleine-Königa602f0f2009-12-17 12:43:29 +010059 unsigned long next, oscr;
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010060
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010061 OIER |= OIER_E0;
Russell King91bc51d2007-11-08 23:35:46 +000062 next = OSCR + delta;
63 OSMR0 = next;
64 oscr = OSCR;
Russell King91bc51d2007-11-08 23:35:46 +000065
66 return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010067}
68
69static void
70pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
71{
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010072 switch (mode) {
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010073 case CLOCK_EVT_MODE_ONESHOT:
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010074 OIER &= ~OIER_E0;
Russell King91bc51d2007-11-08 23:35:46 +000075 OSSR = OSSR_M0;
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010076 break;
77
78 case CLOCK_EVT_MODE_UNUSED:
79 case CLOCK_EVT_MODE_SHUTDOWN:
80 /* initializing, released, or preparing for suspend */
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010081 OIER &= ~OIER_E0;
Russell King91bc51d2007-11-08 23:35:46 +000082 OSSR = OSSR_M0;
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010083 break;
Russell Kingdf433092007-10-27 15:15:49 +010084
85 case CLOCK_EVT_MODE_RESUME:
Russell Kinga88264c2007-11-12 22:45:16 +000086 case CLOCK_EVT_MODE_PERIODIC:
Russell Kingdf433092007-10-27 15:15:49 +010087 break;
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010088 }
89}
90
91static struct clock_event_device ckevt_pxa_osmr0 = {
92 .name = "osmr0",
Russell Kinga88264c2007-11-12 22:45:16 +000093 .features = CLOCK_EVT_FEAT_ONESHOT,
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010094 .rating = 200,
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010095 .set_next_event = pxa_osmr0_set_next_event,
96 .set_mode = pxa_osmr0_set_mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
Bill Gatliff7bbb18c2007-07-21 03:39:36 +010099static struct irqaction pxa_ost0_irq = {
100 .name = "ost0",
101 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
102 .handler = pxa_ost0_interrupt,
103 .dev_id = &ckevt_pxa_osmr0,
104};
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static void __init pxa_timer_init(void)
107{
Eric Miao67697172008-12-18 11:10:32 +0800108 unsigned long clock_tick_rate = get_clock_tick_rate();
Russell King08197f62007-09-01 21:12:50 +0100109
Bill Gatliff7bbb18c2007-07-21 03:39:36 +0100110 OIER = 0;
111 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Marc Zyngier2f0778af2011-12-15 12:19:23 +0100113 setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate);
Nicolas Pitre6c3a1582007-08-17 16:55:22 +0100114
Haojian Zhuangccc46e22010-11-24 11:54:23 +0800115 clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4);
Bill Gatliff7bbb18c2007-07-21 03:39:36 +0100116 ckevt_pxa_osmr0.max_delta_ns =
117 clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
118 ckevt_pxa_osmr0.min_delta_ns =
Russell Kingdd01b2f2008-01-23 12:34:16 +0000119 clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_pxa_osmr0) + 1;
Rusty Russell320ab2b2008-12-13 21:20:26 +1030120 ckevt_pxa_osmr0.cpumask = cpumask_of(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Bill Gatliff7bbb18c2007-07-21 03:39:36 +0100122 setup_irq(IRQ_OST0, &pxa_ost0_irq);
123
Russell King234b6ced2011-05-08 14:09:47 +0100124 clocksource_mmio_init(&OSCR, "oscr0", clock_tick_rate, 200, 32,
125 clocksource_mmio_readl_up);
Bill Gatliff7bbb18c2007-07-21 03:39:36 +0100126 clockevents_register_device(&ckevt_pxa_osmr0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129#ifdef CONFIG_PM
Russell King4ae78062007-11-12 22:48:12 +0000130static unsigned long osmr[4], oier, oscr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132static void pxa_timer_suspend(void)
133{
134 osmr[0] = OSMR0;
135 osmr[1] = OSMR1;
136 osmr[2] = OSMR2;
137 osmr[3] = OSMR3;
138 oier = OIER;
Russell King4ae78062007-11-12 22:48:12 +0000139 oscr = OSCR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
142static void pxa_timer_resume(void)
143{
Russell King4ae78062007-11-12 22:48:12 +0000144 /*
145 * Ensure that we have at least MIN_OSCR_DELTA between match
146 * register 0 and the OSCR, to guarantee that we will receive
147 * the one-shot timer interrupt. We adjust OSMR0 in preference
148 * to OSCR to guarantee that OSCR is monotonically incrementing.
149 */
150 if (osmr[0] - oscr < MIN_OSCR_DELTA)
151 osmr[0] += MIN_OSCR_DELTA;
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 OSMR0 = osmr[0];
154 OSMR1 = osmr[1];
155 OSMR2 = osmr[2];
156 OSMR3 = osmr[3];
157 OIER = oier;
Russell King4ae78062007-11-12 22:48:12 +0000158 OSCR = oscr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159}
160#else
161#define pxa_timer_suspend NULL
162#define pxa_timer_resume NULL
163#endif
164
165struct sys_timer pxa_timer = {
166 .init = pxa_timer_init,
167 .suspend = pxa_timer_suspend,
168 .resume = pxa_timer_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169};