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 29 static DEFINE_RAW_SPINLOCK(gt641xx_timer_lock); 30 static unsigned int gt641xx_base_clock; 31 32 void gt641xx_set_base_clock(unsigned int clock) 33 { 34 gt641xx_base_clock = clock; 35 } 36 37 int 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 48 static int gt641xx_timer0_set_next_event(unsigned long delta, 49 struct clock_event_device *evt) 50 { 51 u32 ctrl; 52 53 raw_spin_lock(>641xx_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(>641xx_timer_lock); 63 64 return 0; 65 } 66 67 static int gt641xx_timer0_shutdown(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 GT_WRITE(GT_TC_CONTROL_OFS, ctrl); 76 77 raw_spin_unlock(>641xx_timer_lock); 78 return 0; 79 } 80 81 static int gt641xx_timer0_set_oneshot(struct clock_event_device *evt) 82 { 83 u32 ctrl; 84 85 raw_spin_lock(>641xx_timer_lock); 86 87 ctrl = GT_READ(GT_TC_CONTROL_OFS); 88 ctrl &= ~GT_TC_CONTROL_SELTC0_MSK; 89 ctrl |= GT_TC_CONTROL_ENTC0_MSK; 90 GT_WRITE(GT_TC_CONTROL_OFS, ctrl); 91 92 raw_spin_unlock(>641xx_timer_lock); 93 return 0; 94 } 95 96 static int gt641xx_timer0_set_periodic(struct clock_event_device *evt) 97 { 98 u32 ctrl; 99 100 raw_spin_lock(>641xx_timer_lock); 101 102 ctrl = GT_READ(GT_TC_CONTROL_OFS); 103 ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; 104 GT_WRITE(GT_TC_CONTROL_OFS, ctrl); 105 106 raw_spin_unlock(>641xx_timer_lock); 107 return 0; 108 } 109 110 static void gt641xx_timer0_event_handler(struct clock_event_device *dev) 111 { 112 } 113 114 static struct clock_event_device gt641xx_timer0_clockevent = { 115 .name = "gt641xx-timer0", 116 .features = CLOCK_EVT_FEAT_PERIODIC | 117 CLOCK_EVT_FEAT_ONESHOT, 118 .irq = GT641XX_TIMER0_IRQ, 119 .set_next_event = gt641xx_timer0_set_next_event, 120 .set_state_shutdown = gt641xx_timer0_shutdown, 121 .set_state_periodic = gt641xx_timer0_set_periodic, 122 .set_state_oneshot = gt641xx_timer0_set_oneshot, 123 .tick_resume = gt641xx_timer0_shutdown, 124 .event_handler = gt641xx_timer0_event_handler, 125 }; 126 127 static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) 128 { 129 struct clock_event_device *cd = >641xx_timer0_clockevent; 130 131 cd->event_handler(cd); 132 133 return IRQ_HANDLED; 134 } 135 136 static struct irqaction gt641xx_timer0_irqaction = { 137 .handler = gt641xx_timer0_interrupt, 138 .flags = IRQF_PERCPU | IRQF_TIMER, 139 .name = "gt641xx_timer0", 140 }; 141 142 static int __init gt641xx_timer0_clockevent_init(void) 143 { 144 struct clock_event_device *cd; 145 146 if (!gt641xx_base_clock) 147 return 0; 148 149 GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ); 150 151 cd = >641xx_timer0_clockevent; 152 cd->rating = 200 + gt641xx_base_clock / 10000000; 153 clockevent_set_clock(cd, gt641xx_base_clock); 154 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); 155 cd->max_delta_ticks = 0x7fffffff; 156 cd->min_delta_ns = clockevent_delta2ns(0x300, cd); 157 cd->min_delta_ticks = 0x300; 158 cd->cpumask = cpumask_of(0); 159 160 clockevents_register_device(>641xx_timer0_clockevent); 161 162 return setup_irq(GT641XX_TIMER0_IRQ, >641xx_timer0_irqaction); 163 } 164 arch_initcall(gt641xx_timer0_clockevent_init); 165