• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* arch/arm/mach-goldfish/timer.c
2 **
3 ** Copyright (C) 2007 Google, Inc.
4 **
5 ** This software is licensed under the terms of the GNU General Public
6 ** License version 2, as published by the Free Software Foundation, and
7 ** may be copied, distributed, and modified under those terms.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU General Public License for more details.
13 **
14 */
15 
16 #include <linux/clockchips.h>
17 #include <linux/interrupt.h>
18 #include <linux/irq.h>
19 
20 #include <mach/timer.h>
21 #include <mach/hardware.h>
22 #include <asm/io.h>
23 #include <asm/mach/time.h>
24 
25 #include <linux/platform_device.h>
26 
27 static DEFINE_SPINLOCK(goldfish_timer_lock);
28 static int goldfish_timer_ready;
29 
goldfish_timer_interrupt(int irq,void * dev_id)30 static irqreturn_t goldfish_timer_interrupt(int irq, void *dev_id)
31 {
32 	uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
33 	struct clock_event_device *evt = dev_id;
34 
35 	writel(1, timer_base + TIMER_CLEAR_INTERRUPT);
36 	if (evt->event_handler)
37 		evt->event_handler(evt);
38 	return IRQ_HANDLED;
39 }
40 
goldfish_timer_read(void)41 static cycle_t goldfish_timer_read(void)
42 {
43 	uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
44 	unsigned long irqflags;
45 	cycle_t rv;
46 
47 	spin_lock_irqsave(&goldfish_timer_lock, irqflags);
48 	rv = readl(timer_base + TIMER_TIME_LOW);
49 	rv |= (int64_t)readl(timer_base + TIMER_TIME_HIGH) << 32;
50 	spin_unlock_irqrestore(&goldfish_timer_lock, irqflags);
51 	return rv;
52 }
53 
goldfish_timer_set_next_event(unsigned long cycles,struct clock_event_device * evt)54 static int goldfish_timer_set_next_event(unsigned long cycles,
55                                          struct clock_event_device *evt)
56 {
57 	uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
58 	unsigned long irqflags;
59 	uint64_t alarm;
60 
61 	spin_lock_irqsave(&goldfish_timer_lock, irqflags);
62 	alarm = readl(timer_base + TIMER_TIME_LOW);
63 	alarm |= (int64_t)readl(timer_base + TIMER_TIME_HIGH) << 32;
64 	alarm += cycles;
65 	writel(alarm >> 32, timer_base + TIMER_ALARM_HIGH);
66 	writel(alarm, timer_base + TIMER_ALARM_LOW);
67 	spin_unlock_irqrestore(&goldfish_timer_lock, irqflags);
68 	return 0;
69 }
70 
goldfish_timer_set_mode(enum clock_event_mode mode,struct clock_event_device * evt)71 static void goldfish_timer_set_mode(enum clock_event_mode mode,
72                                     struct clock_event_device *evt)
73 {
74 	uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
75 	switch (mode) {
76 		case CLOCK_EVT_MODE_RESUME:
77 		case CLOCK_EVT_MODE_PERIODIC:
78 			break;
79 		case CLOCK_EVT_MODE_ONESHOT:
80 			break;
81 		case CLOCK_EVT_MODE_UNUSED:
82 		case CLOCK_EVT_MODE_SHUTDOWN:
83 			writel(1, timer_base + TIMER_CLEAR_ALARM);
84 			break;
85 	}
86 }
87 
sched_clock(void)88 unsigned long long sched_clock(void)
89 {
90 	if(goldfish_timer_ready)
91 		return ktime_to_ns(ktime_get());
92 	else
93 		return 0;
94 }
95 
96 static struct clock_event_device goldfish_clockevent = {
97 	.name           = "goldfish_timer",
98 	.features       = CLOCK_EVT_FEAT_ONESHOT,
99 	.max_delta_ns   = ULONG_MAX,
100 	.min_delta_ns   = 1,
101 	.mult           = 1,
102 	.shift          = 0,
103 	.rating         = 200,
104 	.set_next_event = goldfish_timer_set_next_event,
105 	.set_mode       = goldfish_timer_set_mode,
106 };
107 
108 static struct clocksource goldfish_clocksource = {
109 	.name           = "goldfish_timer",
110 	.rating         = 200,
111 	.read           = goldfish_timer_read,
112 	.mult           = 1,
113 	.mask           = CLOCKSOURCE_MASK(64),
114 	.shift          = 0,
115 	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
116 };
117 
118 static struct irqaction goldfish_timer_irq = {
119 	.name		= "Goldfish Timer Tick",
120 	.flags		= IRQF_DISABLED | IRQF_TIMER,
121 	.handler	= goldfish_timer_interrupt,
122 	.dev_id		= &goldfish_clockevent,
123 };
124 
goldfish_timer_init(void)125 static void __init goldfish_timer_init(void)
126 {
127 	int res;
128 
129 	res = clocksource_register(&goldfish_clocksource);
130 	if (res)
131 		printk(KERN_ERR "goldfish_timer_init: "
132 		       "clocksource_register failed\n");
133 
134 	res = setup_irq(IRQ_TIMER, &goldfish_timer_irq);
135 	if (res)
136 		printk(KERN_ERR "goldfish_timer_init: setup_irq failed\n");
137 
138 	goldfish_clockevent.cpumask = cpumask_of(0);
139 	clockevents_register_device(&goldfish_clockevent);
140 
141 	goldfish_timer_ready = 1;
142 }
143 
144 struct sys_timer goldfish_timer = {
145 	.init		= goldfish_timer_init,
146 };
147 
148