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_RAW_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 raw_spin_lock(>641xx_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 raw_spin_unlock(>641xx_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 raw_spin_lock(>641xx_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 raw_spin_unlock(>641xx_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 = >641xx_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 = >641xx_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(>641xx_timer0_clockevent); 137 138 return setup_irq(GT641XX_TIMER0_IRQ, >641xx_timer0_irqaction); 139} 140arch_initcall(gt641xx_timer0_clockevent_init); 141