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