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 cycle_t 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.min_delta_ns =
  95                clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_puv3_osmr0) + 1;
  96        ckevt_puv3_osmr0.cpumask = cpumask_of(0);
  97
  98        setup_irq(IRQ_TIMER0, &puv3_timer_irq);
  99
 100        clocksource_register_hz(&cksrc_puv3_oscr, CLOCK_TICK_RATE);
 101        clockevents_register_device(&ckevt_puv3_osmr0);
 102}
 103
 104#ifdef CONFIG_PM
 105unsigned long osmr[4], oier;
 106
 107void puv3_timer_suspend(void)
 108{
 109        osmr[0] = readl(OST_OSMR0);
 110        osmr[1] = readl(OST_OSMR1);
 111        osmr[2] = readl(OST_OSMR2);
 112        osmr[3] = readl(OST_OSMR3);
 113        oier = readl(OST_OIER);
 114}
 115
 116void puv3_timer_resume(void)
 117{
 118        writel(0, OST_OSSR);
 119        writel(osmr[0], OST_OSMR0);
 120        writel(osmr[1], OST_OSMR1);
 121        writel(osmr[2], OST_OSMR2);
 122        writel(osmr[3], OST_OSMR3);
 123        writel(oier, OST_OIER);
 124
 125        /*
 126         * OSMR0 is the system timer: make sure OSCR is sufficiently behind
 127         */
 128        writel(readl(OST_OSMR0) - LATCH, OST_OSCR);
 129}
 130#else
 131void puv3_timer_suspend(void) { };
 132void puv3_timer_resume(void) { };
 133#endif
 134
 135