linux/arch/score/kernel/time.c
<<
>>
Prefs
   1/*
   2 * arch/score/kernel/time.c
   3 *
   4 * Score Processor version.
   5 *
   6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
   7 *  Chen Liqin <liqin.chen@sunplusct.com>
   8 *  Lennox Wu <lennox.wu@sunplusct.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, see the file COPYING, or write
  22 * to the Free Software Foundation, Inc.,
  23 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  24 */
  25
  26#include <linux/clockchips.h>
  27#include <linux/interrupt.h>
  28
  29#include <asm/scoreregs.h>
  30
  31static irqreturn_t timer_interrupt(int irq, void *dev_id)
  32{
  33        struct clock_event_device *evdev = dev_id;
  34
  35        /* clear timer interrupt flag */
  36        outl(1, P_TIMER0_CPP_REG);
  37        evdev->event_handler(evdev);
  38
  39        return IRQ_HANDLED;
  40}
  41
  42static struct irqaction timer_irq = {
  43        .handler = timer_interrupt,
  44        .flags = IRQF_DISABLED | IRQF_TIMER,
  45        .name = "timer",
  46};
  47
  48static int score_timer_set_next_event(unsigned long delta,
  49                struct clock_event_device *evdev)
  50{
  51        outl((TMR_M_PERIODIC | TMR_IE_ENABLE), P_TIMER0_CTRL);
  52        outl(delta, P_TIMER0_PRELOAD);
  53        outl(inl(P_TIMER0_CTRL) | TMR_ENABLE, P_TIMER0_CTRL);
  54
  55        return 0;
  56}
  57
  58static void score_timer_set_mode(enum clock_event_mode mode,
  59                struct clock_event_device *evdev)
  60{
  61        switch (mode) {
  62        case CLOCK_EVT_MODE_PERIODIC:
  63                outl((TMR_M_PERIODIC | TMR_IE_ENABLE), P_TIMER0_CTRL);
  64                outl(SYSTEM_CLOCK/HZ, P_TIMER0_PRELOAD);
  65                outl(inl(P_TIMER0_CTRL) | TMR_ENABLE, P_TIMER0_CTRL);
  66                break;
  67        case CLOCK_EVT_MODE_ONESHOT:
  68        case CLOCK_EVT_MODE_SHUTDOWN:
  69        case CLOCK_EVT_MODE_RESUME:
  70        case CLOCK_EVT_MODE_UNUSED:
  71                break;
  72        default:
  73                BUG();
  74        }
  75}
  76
  77static struct clock_event_device score_clockevent = {
  78        .name           = "score_clockevent",
  79        .features       = CLOCK_EVT_FEAT_PERIODIC,
  80        .shift          = 16,
  81        .set_next_event = score_timer_set_next_event,
  82        .set_mode       = score_timer_set_mode,
  83};
  84
  85void __init time_init(void)
  86{
  87        timer_irq.dev_id = &score_clockevent;
  88        setup_irq(IRQ_TIMER , &timer_irq);
  89
  90        /* setup COMPARE clockevent */
  91        score_clockevent.mult = div_sc(SYSTEM_CLOCK, NSEC_PER_SEC,
  92                                        score_clockevent.shift);
  93        score_clockevent.max_delta_ns = clockevent_delta2ns((u32)~0,
  94                                        &score_clockevent);
  95        score_clockevent.min_delta_ns = clockevent_delta2ns(50,
  96                                                &score_clockevent) + 1;
  97        score_clockevent.cpumask = cpumask_of(0);
  98        clockevents_register_device(&score_clockevent);
  99}
 100