Commit | Line | Data |
---|---|---|
7ec80ddf | 1 | /* |
2 | * linux/arch/arm/mach-w90x900/time.c | |
3 | * | |
4 | * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks | |
5 | * | |
58b5369e | 6 | * Copyright (c) 2009 Nuvoton technology corporation |
7ec80ddf | 7 | * All rights reserved. |
8 | * | |
9 | * Wan ZongShun <mcuos.com@gmail.com> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 of the License, or | |
14 | * (at your option) any later version. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/kernel.h> | |
19 | #include <linux/sched.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/interrupt.h> | |
22 | #include <linux/err.h> | |
23 | #include <linux/clk.h> | |
24 | #include <linux/io.h> | |
25 | #include <linux/leds.h> | |
58b5369e | 26 | #include <linux/clocksource.h> |
27 | #include <linux/clockchips.h> | |
7ec80ddf | 28 | |
29 | #include <asm/mach-types.h> | |
30 | #include <asm/mach/irq.h> | |
31 | #include <asm/mach/time.h> | |
32 | ||
7ec80ddf | 33 | #include <mach/map.h> |
1d8f3c49 | 34 | #include "regs-timer.h" |
7ec80ddf | 35 | |
e5bc9e25 RK |
36 | #include "nuc9xx.h" |
37 | ||
58b5369e | 38 | #define RESETINT 0x1f |
39 | #define PERIOD (0x01 << 27) | |
40 | #define ONESHOT (0x00 << 27) | |
41 | #define COUNTEN (0x01 << 30) | |
42 | #define INTEN (0x01 << 29) | |
43 | ||
44 | #define TICKS_PER_SEC 100 | |
45 | #define PRESCALE 0x63 /* Divider = prescale + 1 */ | |
46 | ||
1368c51c | 47 | #define TDR_SHIFT 24 |
1368c51c LJ |
48 | |
49 | static unsigned int timer0_load; | |
58b5369e | 50 | |
6c724d43 | 51 | static int nuc900_clockevent_shutdown(struct clock_event_device *evt) |
7ec80ddf | 52 | { |
6c724d43 | 53 | unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); |
58b5369e | 54 | |
6c724d43 VK |
55 | __raw_writel(val, REG_TCSR0); |
56 | return 0; | |
57 | } | |
58 | ||
59 | static int nuc900_clockevent_set_oneshot(struct clock_event_device *evt) | |
60 | { | |
61 | unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); | |
58b5369e | 62 | |
6c724d43 | 63 | val |= (ONESHOT | COUNTEN | INTEN | PRESCALE); |
58b5369e | 64 | |
6c724d43 VK |
65 | __raw_writel(val, REG_TCSR0); |
66 | return 0; | |
67 | } | |
58b5369e | 68 | |
6c724d43 VK |
69 | static int nuc900_clockevent_set_periodic(struct clock_event_device *evt) |
70 | { | |
71 | unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); | |
58b5369e | 72 | |
6c724d43 VK |
73 | __raw_writel(timer0_load, REG_TICR0); |
74 | val |= (PERIOD | COUNTEN | INTEN | PRESCALE); | |
58b5369e | 75 | __raw_writel(val, REG_TCSR0); |
6c724d43 | 76 | return 0; |
58b5369e | 77 | } |
78 | ||
35c9221a | 79 | static int nuc900_clockevent_setnextevent(unsigned long evt, |
58b5369e | 80 | struct clock_event_device *clk) |
81 | { | |
82 | unsigned int val; | |
83 | ||
84 | __raw_writel(evt, REG_TICR0); | |
85 | ||
86 | val = __raw_readl(REG_TCSR0); | |
87 | val |= (COUNTEN | INTEN | PRESCALE); | |
88 | __raw_writel(val, REG_TCSR0); | |
89 | ||
7ec80ddf | 90 | return 0; |
91 | } | |
92 | ||
35c9221a | 93 | static struct clock_event_device nuc900_clockevent_device = { |
6c724d43 VK |
94 | .name = "nuc900-timer0", |
95 | .features = CLOCK_EVT_FEAT_PERIODIC | | |
96 | CLOCK_EVT_FEAT_ONESHOT, | |
97 | .set_state_shutdown = nuc900_clockevent_shutdown, | |
98 | .set_state_periodic = nuc900_clockevent_set_periodic, | |
99 | .set_state_oneshot = nuc900_clockevent_set_oneshot, | |
100 | .tick_resume = nuc900_clockevent_shutdown, | |
101 | .set_next_event = nuc900_clockevent_setnextevent, | |
102 | .rating = 300, | |
58b5369e | 103 | }; |
104 | ||
7ec80ddf | 105 | /*IRQ handler for the timer*/ |
106 | ||
35c9221a | 107 | static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id) |
7ec80ddf | 108 | { |
35c9221a | 109 | struct clock_event_device *evt = &nuc900_clockevent_device; |
58b5369e | 110 | |
7ec80ddf | 111 | __raw_writel(0x01, REG_TISR); /* clear TIF0 */ |
58b5369e | 112 | |
113 | evt->event_handler(evt); | |
7ec80ddf | 114 | return IRQ_HANDLED; |
115 | } | |
116 | ||
35c9221a | 117 | static struct irqaction nuc900_timer0_irq = { |
118 | .name = "nuc900-timer0", | |
2ed71e75 | 119 | .flags = IRQF_TIMER | IRQF_IRQPOLL, |
35c9221a | 120 | .handler = nuc900_timer0_interrupt, |
7ec80ddf | 121 | }; |
122 | ||
1368c51c | 123 | static void __init nuc900_clockevents_init(void) |
58b5369e | 124 | { |
1368c51c LJ |
125 | unsigned int rate; |
126 | struct clk *clk = clk_get(NULL, "timer0"); | |
127 | ||
128 | BUG_ON(IS_ERR(clk)); | |
129 | ||
130 | __raw_writel(0x00, REG_TCSR0); | |
131 | ||
132 | clk_enable(clk); | |
133 | rate = clk_get_rate(clk) / (PRESCALE + 1); | |
134 | ||
135 | timer0_load = (rate / TICKS_PER_SEC); | |
136 | ||
137 | __raw_writel(RESETINT, REG_TISR); | |
138 | setup_irq(IRQ_TIMER0, &nuc900_timer0_irq); | |
139 | ||
35c9221a | 140 | nuc900_clockevent_device.cpumask = cpumask_of(0); |
141 | ||
838a2ae8 SG |
142 | clockevents_config_and_register(&nuc900_clockevent_device, rate, |
143 | 0xf, 0xffffffff); | |
58b5369e | 144 | } |
145 | ||
1368c51c | 146 | static void __init nuc900_clocksource_init(void) |
7ec80ddf | 147 | { |
58b5369e | 148 | unsigned int val; |
1368c51c LJ |
149 | unsigned int rate; |
150 | struct clk *clk = clk_get(NULL, "timer1"); | |
151 | ||
152 | BUG_ON(IS_ERR(clk)); | |
153 | ||
154 | __raw_writel(0x00, REG_TCSR1); | |
155 | ||
156 | clk_enable(clk); | |
157 | rate = clk_get_rate(clk) / (PRESCALE + 1); | |
58b5369e | 158 | |
159 | __raw_writel(0xffffffff, REG_TICR1); | |
160 | ||
161 | val = __raw_readl(REG_TCSR1); | |
1368c51c | 162 | val |= (COUNTEN | PERIOD | PRESCALE); |
58b5369e | 163 | __raw_writel(val, REG_TCSR1); |
164 | ||
6fa5d5f7 RK |
165 | clocksource_mmio_init(REG_TDR1, "nuc900-timer1", rate, 200, |
166 | TDR_SHIFT, clocksource_mmio_readl_down); | |
58b5369e | 167 | } |
168 | ||
6bb27d73 | 169 | void __init nuc900_timer_init(void) |
58b5369e | 170 | { |
1368c51c LJ |
171 | nuc900_clocksource_init(); |
172 | nuc900_clockevents_init(); | |
7ec80ddf | 173 | } |