linux/arch/mips/kernel/cevt-gt641xx.c
<<
>>
Prefs
   1/*
   2 *  GT641xx clockevent routines.
   3 *
   4 *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19 */
  20#include <linux/clockchips.h>
  21#include <linux/init.h>
  22#include <linux/interrupt.h>
  23#include <linux/spinlock.h>
  24
  25#include <asm/gt64120.h>
  26#include <asm/time.h>
  27
  28static DEFINE_SPINLOCK(gt641xx_timer_lock);
  29static unsigned int gt641xx_base_clock;
  30
  31void gt641xx_set_base_clock(unsigned int clock)
  32{
  33        gt641xx_base_clock = clock;
  34}
  35
  36int gt641xx_timer0_state(void)
  37{
  38        if (GT_READ(GT_TC0_OFS))
  39                return 0;
  40
  41        GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
  42        GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
  43
  44        return 1;
  45}
  46
  47static int gt641xx_timer0_set_next_event(unsigned long delta,
  48                                         struct clock_event_device *evt)
  49{
  50        u32 ctrl;
  51
  52        spin_lock(&gt641xx_timer_lock);
  53
  54        ctrl = GT_READ(GT_TC_CONTROL_OFS);
  55        ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
  56        ctrl |= GT_TC_CONTROL_ENTC0_MSK;
  57
  58        GT_WRITE(GT_TC0_OFS, delta);
  59        GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
  60
  61        spin_unlock(&gt641xx_timer_lock);
  62
  63        return 0;
  64}
  65
  66static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
  67                                    struct clock_event_device *evt)
  68{
  69        u32 ctrl;
  70
  71        spin_lock(&gt641xx_timer_lock);
  72
  73        ctrl = GT_READ(GT_TC_CONTROL_OFS);
  74        ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
  75
  76        switch (mode) {
  77        case CLOCK_EVT_MODE_PERIODIC:
  78                ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
  79                break;
  80        case CLOCK_EVT_MODE_ONESHOT:
  81                ctrl |= GT_TC_CONTROL_ENTC0_MSK;
  82                break;
  83        default:
  84                break;
  85        }
  86
  87        GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
  88
  89        spin_unlock(&gt641xx_timer_lock);
  90}
  91
  92static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
  93{
  94}
  95
  96static struct clock_event_device gt641xx_timer0_clockevent = {
  97        .name           = "gt641xx-timer0",
  98        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  99        .irq            = GT641XX_TIMER0_IRQ,
 100        .set_next_event = gt641xx_timer0_set_next_event,
 101        .set_mode       = gt641xx_timer0_set_mode,
 102        .event_handler  = gt641xx_timer0_event_handler,
 103};
 104
 105static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
 106{
 107        struct clock_event_device *cd = &gt641xx_timer0_clockevent;
 108
 109        cd->event_handler(cd);
 110
 111        return IRQ_HANDLED;
 112}
 113
 114static struct irqaction gt641xx_timer0_irqaction = {
 115        .handler        = gt641xx_timer0_interrupt,
 116        .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 117        .name           = "gt641xx_timer0",
 118};
 119
 120static int __init gt641xx_timer0_clockevent_init(void)
 121{
 122        struct clock_event_device *cd;
 123
 124        if (!gt641xx_base_clock)
 125                return 0;
 126
 127        GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
 128
 129        cd = &gt641xx_timer0_clockevent;
 130        cd->rating = 200 + gt641xx_base_clock / 10000000;
 131        clockevent_set_clock(cd, gt641xx_base_clock);
 132        cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
 133        cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
 134        cd->cpumask = cpumask_of(0);
 135
 136        clockevents_register_device(&gt641xx_timer0_clockevent);
 137
 138        return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
 139}
 140arch_initcall(gt641xx_timer0_clockevent_init);
 141