• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/plat-stmp3xxx/
1/*
2 * System timer for Freescale STMP37XX/STMP378X
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/clocksource.h>
22#include <linux/clockchips.h>
23#include <linux/io.h>
24#include <linux/irq.h>
25#include <linux/interrupt.h>
26
27#include <asm/mach/time.h>
28#include <mach/stmp3xxx.h>
29#include <mach/platform.h>
30#include <mach/regs-timrot.h>
31
32static irqreturn_t
33stmp3xxx_timer_interrupt(int irq, void *dev_id)
34{
35	struct clock_event_device *c = dev_id;
36
37	/* timer 0 */
38	if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
39			BM_TIMROT_TIMCTRLn_IRQ) {
40		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
41				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
42		c->event_handler(c);
43	}
44
45	/* timer 1 */
46	else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
47			& BM_TIMROT_TIMCTRLn_IRQ) {
48		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
49				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
50		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
51				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
52		__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
53	}
54
55	return IRQ_HANDLED;
56}
57
58static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
59{
60	return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
61				& 0xFFFF0000) >> 16);
62}
63
64static int
65stmp3xxx_timrot_set_next_event(unsigned long delta,
66		struct clock_event_device *dev)
67{
68	/* reload the timer */
69	__raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
70	return 0;
71}
72
73static void
74stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
75		struct clock_event_device *dev)
76{
77}
78
79static struct clock_event_device ckevt_timrot = {
80	.name		= "timrot",
81	.features	= CLOCK_EVT_FEAT_ONESHOT,
82	.shift		= 32,
83	.set_next_event	= stmp3xxx_timrot_set_next_event,
84	.set_mode	= stmp3xxx_timrot_set_mode,
85};
86
87static struct clocksource cksrc_stmp3xxx = {
88	.name           = "cksrc_stmp3xxx",
89	.rating         = 250,
90	.read           = stmp3xxx_clock_read,
91	.mask           = CLOCKSOURCE_MASK(16),
92	.shift          = 10,
93	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
94};
95
96static struct irqaction stmp3xxx_timer_irq = {
97	.name		= "stmp3xxx_timer",
98	.flags		= IRQF_DISABLED | IRQF_TIMER,
99	.handler	= stmp3xxx_timer_interrupt,
100	.dev_id		= &ckevt_timrot,
101};
102
103
104/*
105 * Set up timer interrupt, and return the current time in seconds.
106 */
107static void __init stmp3xxx_init_timer(void)
108{
109	cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
110				cksrc_stmp3xxx.shift);
111	ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
112				ckevt_timrot.shift);
113	ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
114	ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
115	ckevt_timrot.cpumask = cpumask_of(0);
116
117	stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
118
119	/* clear two timers */
120	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
121	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
122
123	/* configure them */
124	__raw_writel(
125		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
126		BM_TIMROT_TIMCTRLn_RELOAD |
127		BM_TIMROT_TIMCTRLn_UPDATE |
128		BM_TIMROT_TIMCTRLn_IRQ_EN,
129			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
130	__raw_writel(
131		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
132		BM_TIMROT_TIMCTRLn_RELOAD |
133		BM_TIMROT_TIMCTRLn_UPDATE |
134		BM_TIMROT_TIMCTRLn_IRQ_EN,
135			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
136
137	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
138			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
139	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
140
141	setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
142
143	clocksource_register(&cksrc_stmp3xxx);
144	clockevents_register_device(&ckevt_timrot);
145}
146
147#ifdef CONFIG_PM
148
149void stmp3xxx_suspend_timer(void)
150{
151	stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
152			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
153	stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
154			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
155}
156
157void stmp3xxx_resume_timer(void)
158{
159	stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
160			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
161	__raw_writel(
162		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
163		BM_TIMROT_TIMCTRLn_RELOAD |
164		BM_TIMROT_TIMCTRLn_UPDATE |
165		BM_TIMROT_TIMCTRLn_IRQ_EN,
166			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
167	__raw_writel(
168		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
169		BM_TIMROT_TIMCTRLn_RELOAD |
170		BM_TIMROT_TIMCTRLn_UPDATE |
171		BM_TIMROT_TIMCTRLn_IRQ_EN,
172			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
173	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
174			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
175	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
176}
177
178#else
179
180#define stmp3xxx_suspend_timer	NULL
181#define	stmp3xxx_resume_timer	NULL
182
183#endif	/* CONFIG_PM */
184
185struct sys_timer stmp3xxx_timer = {
186	.init		= stmp3xxx_init_timer,
187	.suspend	= stmp3xxx_suspend_timer,
188	.resume		= stmp3xxx_resume_timer,
189};
190