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 28 static DEFINE_SPINLOCK(gt641xx_timer_lock); 29 static unsigned int gt641xx_base_clock; 30 31 void gt641xx_set_base_clock(unsigned int clock) 32 { 33 gt641xx_base_clock = clock; 34 } 35 36 int 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 47 static int gt641xx_timer0_set_next_event(unsigned long delta, 48 struct clock_event_device *evt) 49 { 50 u32 ctrl; 51 52 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 spin_unlock(>641xx_timer_lock); 62 63 return 0; 64 } 65 66 static void gt641xx_timer0_set_mode(enum clock_event_mode mode, 67 struct clock_event_device *evt) 68 { 69 u32 ctrl; 70 71 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 spin_unlock(>641xx_timer_lock); 90 } 91 92 static void gt641xx_timer0_event_handler(struct clock_event_device *dev) 93 { 94 } 95 96 static 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 105 static 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 114 static struct irqaction gt641xx_timer0_irqaction = { 115 .handler = gt641xx_timer0_interrupt, 116 .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, 117 .name = "gt641xx_timer0", 118 }; 119 120 static 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 } 140 arch_initcall(gt641xx_timer0_clockevent_init); 141