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#include <linux/irq.h>
  25
  26#include <asm/gt64120.h>
  27#include <asm/time.h>
  28
  29static DEFINE_RAW_SPINLOCK(gt641xx_timer_lock);
  30static unsigned int gt641xx_base_clock;
  31
  32void gt641xx_set_base_clock(unsigned int clock)
  33{
  34        gt641xx_base_clock = clock;
  35}
  36
  37int gt641xx_timer0_state(void)
  38{
  39        if (GT_READ(GT_TC0_OFS))
  40                return 0;
  41
  42        GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
  43        GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
  44
  45        return 1;
  46}
  47
  48static int gt641xx_timer0_set_next_event(unsigned long delta,
  49                                         struct clock_event_device *evt)
  50{
  51        u32 ctrl;
  52
  53        raw_spin_lock(&gt641xx_timer_lock);
  54
  55        ctrl = GT_READ(GT_TC_CONTROL_OFS);
  56        ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
  57        ctrl |= GT_TC_CONTROL_ENTC0_MSK;
  58
  59        GT_WRITE(GT_TC0_OFS, delta);
  60        GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
  61
  62        raw_spin_unlock(&gt641xx_timer_lock);
  63
  64        return 0;
  65}
  66
  67static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
  68                                    struct clock_event_device *evt)
  69{
  70        u32 ctrl;
  71
  72        raw_spin_lock(&gt641xx_timer_lock);
  73
  74        ctrl = GT_READ(GT_TC_CONTROL_OFS);
  75        ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
  76
  77        switch (mode) {
  78        case CLOCK_EVT_MODE_PERIODIC:
  79                ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
  80                break;
  81        case CLOCK_EVT_MODE_ONESHOT:
  82                ctrl |= GT_TC_CONTROL_ENTC0_MSK;
  83                break;
  84        default:
  85                break;
  86        }
  87
  88        GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
  89
  90        raw_spin_unlock(&gt641xx_timer_lock);
  91}
  92
  93static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
  94{
  95}
  96
  97static struct clock_event_device gt641xx_timer0_clockevent = {
  98        .name           = "gt641xx-timer0",
  99        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 100        .irq            = GT641XX_TIMER0_IRQ,
 101        .set_next_event = gt641xx_timer0_set_next_event,
 102        .set_mode       = gt641xx_timer0_set_mode,
 103        .event_handler  = gt641xx_timer0_event_handler,
 104};
 105
 106static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
 107{
 108        struct clock_event_device *cd = &gt641xx_timer0_clockevent;
 109
 110        cd->event_handler(cd);
 111
 112        return IRQ_HANDLED;
 113}
 114
 115static struct irqaction gt641xx_timer0_irqaction = {
 116        .handler        = gt641xx_timer0_interrupt,
 117        .flags          = IRQF_PERCPU | IRQF_TIMER,
 118        .name           = "gt641xx_timer0",
 119};
 120
 121static int __init gt641xx_timer0_clockevent_init(void)
 122{
 123        struct clock_event_device *cd;
 124
 125        if (!gt641xx_base_clock)
 126                return 0;
 127
 128        GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
 129
 130        cd = &gt641xx_timer0_clockevent;
 131        cd->rating = 200 + gt641xx_base_clock / 10000000;
 132        clockevent_set_clock(cd, gt641xx_base_clock);
 133        cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
 134        cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
 135        cd->cpumask = cpumask_of(0);
 136
 137        clockevents_register_device(&gt641xx_timer0_clockevent);
 138
 139        return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
 140}
 141arch_initcall(gt641xx_timer0_clockevent_init);
 142