linux/arch/arm/mach-sa1100/time.c
<<
>>
Prefs
   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
  23static 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
  35static int
  36sa1100_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
  50static void
  51sa1100_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
  71static struct clock_event_device ckevt_sa1100_osmr0 = {
  72        .name           = "osmr0",
  73        .features       = CLOCK_EVT_FEAT_ONESHOT,
  74        .shift          = 32,
  75        .rating         = 200,
  76        .cpumask        = CPU_MASK_CPU0,
  77        .set_next_event = sa1100_osmr0_set_next_event,
  78        .set_mode       = sa1100_osmr0_set_mode,
  79};
  80
  81static cycle_t sa1100_read_oscr(void)
  82{
  83        return OSCR;
  84}
  85
  86static struct clocksource cksrc_sa1100_oscr = {
  87        .name           = "oscr",
  88        .rating         = 200,
  89        .read           = sa1100_read_oscr,
  90        .mask           = CLOCKSOURCE_MASK(32),
  91        .shift          = 20,
  92        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  93};
  94
  95static struct irqaction sa1100_timer_irq = {
  96        .name           = "ost0",
  97        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
  98        .handler        = sa1100_ost0_interrupt,
  99        .dev_id         = &ckevt_sa1100_osmr0,
 100};
 101
 102static void __init sa1100_timer_init(void)
 103{
 104        OIER = 0;               /* disable any timer interrupts */
 105        OSSR = 0xf;             /* clear status on all timers */
 106
 107        ckevt_sa1100_osmr0.mult =
 108                div_sc(3686400, NSEC_PER_SEC, ckevt_sa1100_osmr0.shift);
 109        ckevt_sa1100_osmr0.max_delta_ns =
 110                clockevent_delta2ns(0x7fffffff, &ckevt_sa1100_osmr0);
 111        ckevt_sa1100_osmr0.min_delta_ns =
 112                clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_sa1100_osmr0) + 1;
 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
 124unsigned long osmr[4], oier;
 125
 126static 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
 135static 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
 154struct sys_timer sa1100_timer = {
 155        .init           = sa1100_timer_init,
 156        .suspend        = sa1100_timer_suspend,
 157        .resume         = sa1100_timer_resume,
 158};
 159