linux/arch/unicore32/kernel/time.c
<<
>>
Prefs
   1/*
   2 * linux/arch/unicore32/kernel/time.c
   3 *
   4 * Code specific to PKUnity SoC and UniCore ISA
   5 *
   6 *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
   7 *      Copyright (C) 2001-2010 Guan Xuetao
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13#include <linux/init.h>
  14#include <linux/errno.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/timex.h>
  18#include <linux/clockchips.h>
  19
  20#include <mach/hardware.h>
  21
  22#define MIN_OSCR_DELTA 2
  23
  24static irqreturn_t puv3_ost0_interrupt(int irq, void *dev_id)
  25{
  26        struct clock_event_device *c = dev_id;
  27
  28        /* Disarm the compare/match, signal the event. */
  29        writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
  30        writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
  31        c->event_handler(c);
  32
  33        return IRQ_HANDLED;
  34}
  35
  36static int
  37puv3_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
  38{
  39        unsigned long next, oscr;
  40
  41        writel(readl(OST_OIER) | OST_OIER_E0, OST_OIER);
  42        next = readl(OST_OSCR) + delta;
  43        writel(next, OST_OSMR0);
  44        oscr = readl(OST_OSCR);
  45
  46        return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
  47}
  48
  49static int puv3_osmr0_shutdown(struct clock_event_device *evt)
  50{
  51        writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
  52        writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
  53        return 0;
  54}
  55
  56static struct clock_event_device ckevt_puv3_osmr0 = {
  57        .name                   = "osmr0",
  58        .features               = CLOCK_EVT_FEAT_ONESHOT,
  59        .rating                 = 200,
  60        .set_next_event         = puv3_osmr0_set_next_event,
  61        .set_state_shutdown     = puv3_osmr0_shutdown,
  62        .set_state_oneshot      = puv3_osmr0_shutdown,
  63};
  64
  65static u64 puv3_read_oscr(struct clocksource *cs)
  66{
  67        return readl(OST_OSCR);
  68}
  69
  70static struct clocksource cksrc_puv3_oscr = {
  71        .name           = "oscr",
  72        .rating         = 200,
  73        .read           = puv3_read_oscr,
  74        .mask           = CLOCKSOURCE_MASK(32),
  75        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  76};
  77
  78static struct irqaction puv3_timer_irq = {
  79        .name           = "ost0",
  80        .flags          = IRQF_TIMER | IRQF_IRQPOLL,
  81        .handler        = puv3_ost0_interrupt,
  82        .dev_id         = &ckevt_puv3_osmr0,
  83};
  84
  85void __init time_init(void)
  86{
  87        writel(0, OST_OIER);            /* disable any timer interrupts */
  88        writel(0, OST_OSSR);            /* clear status on all timers */
  89
  90        clockevents_calc_mult_shift(&ckevt_puv3_osmr0, CLOCK_TICK_RATE, 5);
  91
  92        ckevt_puv3_osmr0.max_delta_ns =
  93                clockevent_delta2ns(0x7fffffff, &ckevt_puv3_osmr0);
  94        ckevt_puv3_osmr0.max_delta_ticks = 0x7fffffff;
  95        ckevt_puv3_osmr0.min_delta_ns =
  96                clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_puv3_osmr0) + 1;
  97        ckevt_puv3_osmr0.min_delta_ticks = MIN_OSCR_DELTA * 2;
  98        ckevt_puv3_osmr0.cpumask = cpumask_of(0);
  99
 100        setup_irq(IRQ_TIMER0, &puv3_timer_irq);
 101
 102        clocksource_register_hz(&cksrc_puv3_oscr, CLOCK_TICK_RATE);
 103        clockevents_register_device(&ckevt_puv3_osmr0);
 104}
 105
 106#ifdef CONFIG_PM
 107unsigned long osmr[4], oier;
 108
 109void puv3_timer_suspend(void)
 110{
 111        osmr[0] = readl(OST_OSMR0);
 112        osmr[1] = readl(OST_OSMR1);
 113        osmr[2] = readl(OST_OSMR2);
 114        osmr[3] = readl(OST_OSMR3);
 115        oier = readl(OST_OIER);
 116}
 117
 118void puv3_timer_resume(void)
 119{
 120        writel(0, OST_OSSR);
 121        writel(osmr[0], OST_OSMR0);
 122        writel(osmr[1], OST_OSMR1);
 123        writel(osmr[2], OST_OSMR2);
 124        writel(osmr[3], OST_OSMR3);
 125        writel(oier, OST_OIER);
 126
 127        /*
 128         * OSMR0 is the system timer: make sure OSCR is sufficiently behind
 129         */
 130        writel(readl(OST_OSMR0) - LATCH, OST_OSCR);
 131}
 132#else
 133void puv3_timer_suspend(void) { };
 134void puv3_timer_resume(void) { };
 135#endif
 136
 137