• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-netx/
1/*
2 * arch/arm/mach-netx/time.c
3 *
4 * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
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 version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/clocksource.h>
24#include <linux/clockchips.h>
25#include <linux/io.h>
26
27#include <mach/hardware.h>
28#include <asm/mach/time.h>
29#include <mach/netx-regs.h>
30
31#define TIMER_CLOCKEVENT 0
32#define TIMER_CLOCKSOURCE 1
33
34static void netx_set_mode(enum clock_event_mode mode,
35		struct clock_event_device *clk)
36{
37	u32 tmode;
38
39	/* disable timer */
40	writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));
41
42	switch (mode) {
43	case CLOCK_EVT_MODE_PERIODIC:
44		writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
45		tmode = NETX_GPIO_COUNTER_CTRL_RST_EN |
46			NETX_GPIO_COUNTER_CTRL_IRQ_EN |
47			NETX_GPIO_COUNTER_CTRL_RUN;
48		break;
49
50	case CLOCK_EVT_MODE_ONESHOT:
51		writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
52		tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN |
53			NETX_GPIO_COUNTER_CTRL_RUN;
54		break;
55
56	default:
57		WARN(1, "%s: unhandled mode %d\n", __func__, mode);
58		/* fall through */
59
60	case CLOCK_EVT_MODE_SHUTDOWN:
61	case CLOCK_EVT_MODE_UNUSED:
62	case CLOCK_EVT_MODE_RESUME:
63		tmode = 0;
64		break;
65	}
66
67	writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));
68}
69
70static int netx_set_next_event(unsigned long evt,
71		struct clock_event_device *clk)
72{
73	writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT));
74	return 0;
75}
76
77static struct clock_event_device netx_clockevent = {
78	.name = "netx-timer" __stringify(TIMER_CLOCKEVENT),
79	.shift = 32,
80	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
81	.set_next_event = netx_set_next_event,
82	.set_mode = netx_set_mode,
83};
84
85/*
86 * IRQ handler for the timer
87 */
88static irqreturn_t
89netx_timer_interrupt(int irq, void *dev_id)
90{
91	struct clock_event_device *evt = &netx_clockevent;
92
93	/* acknowledge interrupt */
94	writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
95
96	evt->event_handler(evt);
97
98	return IRQ_HANDLED;
99}
100
101static struct irqaction netx_timer_irq = {
102	.name		= "NetX Timer Tick",
103	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
104	.handler	= netx_timer_interrupt,
105};
106
107cycle_t netx_get_cycles(struct clocksource *cs)
108{
109	return readl(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE));
110}
111
112static struct clocksource clocksource_netx = {
113	.name		= "netx_timer",
114	.rating		= 200,
115	.read		= netx_get_cycles,
116	.mask		= CLOCKSOURCE_MASK(32),
117	.shift		= 20,
118	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
119};
120
121/*
122 * Set up timer interrupt
123 */
124static void __init netx_timer_init(void)
125{
126	/* disable timer initially */
127	writel(0, NETX_GPIO_COUNTER_CTRL(0));
128
129	/* Reset the timer value to zero */
130	writel(0, NETX_GPIO_COUNTER_CURRENT(0));
131
132	writel(LATCH, NETX_GPIO_COUNTER_MAX(0));
133
134	/* acknowledge interrupt */
135	writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
136
137	/* Enable the interrupt in the specific timer
138	 * register and start timer
139	 */
140	writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE);
141	writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN,
142			NETX_GPIO_COUNTER_CTRL(0));
143
144	setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq);
145
146	/* Setup timer one for clocksource */
147	writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE));
148	writel(0, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE));
149	writel(0xffffffff, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKSOURCE));
150
151	writel(NETX_GPIO_COUNTER_CTRL_RUN,
152			NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE));
153
154	clocksource_netx.mult =
155		clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift);
156	clocksource_register(&clocksource_netx);
157
158	netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
159			netx_clockevent.shift);
160	netx_clockevent.max_delta_ns =
161		clockevent_delta2ns(0xfffffffe, &netx_clockevent);
162	/* with max_delta_ns >= delta2ns(0x800) the system currently runs fine.
163	 * Adding some safety ... */
164	netx_clockevent.min_delta_ns =
165		clockevent_delta2ns(0xa00, &netx_clockevent);
166	netx_clockevent.cpumask = cpumask_of(0);
167	clockevents_register_device(&netx_clockevent);
168}
169
170struct sys_timer netx_timer = {
171	.init		= netx_timer_init,
172};
173