aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pnx4008/time.c
diff options
context:
space:
mode:
authorVitaly Wool <vwool@ru.mvista.com>2006-05-16 06:54:37 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-18 11:16:55 -0400
commit78818e477bf785391b02672d053fdbb2e111fb50 (patch)
treed1a43ddfb1b966fe981c10c874bae4faad070f29 /arch/arm/mach-pnx4008/time.c
parenta5a503038e71a6b7d4bd9e596ac13087274e60c7 (diff)
[ARM] 3466/1: [2/3] Support for Philips PNX4008 platform: chip support
Patch from Vitaly Wool This patch adds basic chip support for PNX4008 ARM platform. It's basically the same as the previous one, but with the rmk's comments taken into account. Signed-off-by: Vitaly Wool <vwool@ru.mvista.com> Signed-off-by: Dmitry Pervushin <dpervushin@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-pnx4008/time.c')
-rw-r--r--arch/arm/mach-pnx4008/time.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
new file mode 100644
index 000000000000..4ce680698529
--- /dev/null
+++ b/arch/arm/mach-pnx4008/time.c
@@ -0,0 +1,141 @@
1/*
2 * arch/arm/mach-pnx4008/time.c
3 *
4 * PNX4008 Timers
5 *
6 * Authors: Vitaly Wool, Dmitry Chigirev, Grigory Tolstolytkin <source@mvista.com>
7 *
8 * 2005 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14#include <linux/config.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/spinlock.h>
21#include <linux/module.h>
22#include <linux/kallsyms.h>
23
24#include <asm/system.h>
25#include <asm/hardware.h>
26#include <asm/io.h>
27#include <asm/leds.h>
28#include <asm/irq.h>
29#include <asm/mach/irq.h>
30#include <asm/mach/time.h>
31
32#include <linux/time.h>
33#include <linux/timex.h>
34#include <asm/errno.h>
35
36/*! Note: all timers are UPCOUNTING */
37
38/*!
39 * Returns number of us since last clock interrupt. Note that interrupts
40 * will have been disabled by do_gettimeoffset()
41 */
42static unsigned long pnx4008_gettimeoffset(void)
43{
44 u32 ticks_to_match =
45 __raw_readl(HSTIM_MATCH0) - __raw_readl(HSTIM_COUNTER);
46 u32 elapsed = LATCH - ticks_to_match;
47 return (elapsed * (tick_nsec / 1000)) / LATCH;
48}
49
50/*!
51 * IRQ handler for the timer
52 */
53static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id,
54 struct pt_regs *regs)
55{
56 if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
57
58 write_seqlock(&xtime_lock);
59
60 do {
61 timer_tick(regs);
62
63 /*
64 * this algorithm takes care of possible delay
65 * for this interrupt handling longer than a normal
66 * timer period
67 */
68 __raw_writel(__raw_readl(HSTIM_MATCH0) + LATCH,
69 HSTIM_MATCH0);
70 __raw_writel(MATCH0_INT, HSTIM_INT); /* clear interrupt */
71
72 /*
73 * The goal is to keep incrementing HSTIM_MATCH0
74 * register until HSTIM_MATCH0 indicates time after
75 * what HSTIM_COUNTER indicates.
76 */
77 } while ((signed)
78 (__raw_readl(HSTIM_MATCH0) -
79 __raw_readl(HSTIM_COUNTER)) < 0);
80
81 write_sequnlock(&xtime_lock);
82 }
83
84 return IRQ_HANDLED;
85}
86
87static struct irqaction pnx4008_timer_irq = {
88 .name = "PNX4008 Tick Timer",
89 .flags = SA_INTERRUPT | SA_TIMER,
90 .handler = pnx4008_timer_interrupt
91};
92
93/*!
94 * Set up timer and timer interrupt.
95 */
96static __init void pnx4008_setup_timer(void)
97{
98 __raw_writel(RESET_COUNT, MSTIM_CTRL);
99 while (__raw_readl(MSTIM_COUNTER)) ; /* wait for reset to complete. 100% guarantee event */
100 __raw_writel(0, MSTIM_CTRL); /* stop the timer */
101 __raw_writel(0, MSTIM_MCTRL);
102
103 __raw_writel(RESET_COUNT, HSTIM_CTRL);
104 while (__raw_readl(HSTIM_COUNTER)) ; /* wait for reset to complete. 100% guarantee event */
105 __raw_writel(0, HSTIM_CTRL);
106 __raw_writel(0, HSTIM_MCTRL);
107 __raw_writel(0, HSTIM_CCR);
108 __raw_writel(12, HSTIM_PMATCH); /* scale down to 1 MHZ */
109 __raw_writel(LATCH, HSTIM_MATCH0);
110 __raw_writel(MR0_INT, HSTIM_MCTRL);
111
112 setup_irq(HSTIMER_INT, &pnx4008_timer_irq);
113
114 __raw_writel(COUNT_ENAB | DEBUG_EN, HSTIM_CTRL); /*start timer, stop when JTAG active */
115}
116
117/* Timer Clock Control in PM register */
118#define TIMCLK_CTRL_REG IO_ADDRESS((PNX4008_PWRMAN_BASE + 0xBC))
119#define WATCHDOG_CLK_EN 1
120#define TIMER_CLK_EN 2 /* HS and MS timers? */
121
122static u32 timclk_ctrl_reg_save;
123
124void pnx4008_timer_suspend(void)
125{
126 timclk_ctrl_reg_save = __raw_readl(TIMCLK_CTRL_REG);
127 __raw_writel(0, TIMCLK_CTRL_REG); /* disable timers */
128}
129
130void pnx4008_timer_resume(void)
131{
132 __raw_writel(timclk_ctrl_reg_save, TIMCLK_CTRL_REG); /* enable timers */
133}
134
135struct sys_timer pnx4008_timer = {
136 .init = pnx4008_setup_timer,
137 .offset = pnx4008_gettimeoffset,
138 .suspend = pnx4008_timer_suspend,
139 .resume = pnx4008_timer_resume,
140};
141