aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwanzongshun <mcuos.com@gmail.com>2009-08-14 10:36:44 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-08-15 10:49:02 -0400
commit58b5369e6eb6c889b540a99aa95562a66b25acf1 (patch)
tree2fd98268bc19e2e7de3b7cafb09229975fada364
parentae45b1c618d9e645a5e1decff31b710f739745fa (diff)
ARM: 5674/1: Add clocksource/clockevent support for w90p910 platform
Add clocksource/clockevent support for w90p910 platform. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/mach-w90x900/clock.c6
-rw-r--r--arch/arm/mach-w90x900/time.c151
-rw-r--r--arch/arm/mach-w90x900/w90p910.c2
4 files changed, 137 insertions, 24 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c3fed1ee7304..8c4f03d34124 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -495,6 +495,8 @@ config ARCH_W90X900
495 select GENERIC_GPIO 495 select GENERIC_GPIO
496 select HAVE_CLK 496 select HAVE_CLK
497 select COMMON_CLKDEV 497 select COMMON_CLKDEV
498 select GENERIC_TIME
499 select GENERIC_CLOCKEVENTS
498 help 500 help
499 Support for Nuvoton (Winbond logic dept.) ARM9 processor,You 501 Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
500 can login www.mcuos.com or www.nuvoton.com to know more. 502 can login www.mcuos.com or www.nuvoton.com to know more.
diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
index 49cf1fbc14eb..70b671096377 100644
--- a/arch/arm/mach-w90x900/clock.c
+++ b/arch/arm/mach-w90x900/clock.c
@@ -55,6 +55,12 @@ void clk_disable(struct clk *clk)
55} 55}
56EXPORT_SYMBOL(clk_disable); 56EXPORT_SYMBOL(clk_disable);
57 57
58unsigned long clk_get_rate(struct clk *clk)
59{
60 return 15000000;
61}
62EXPORT_SYMBOL(clk_get_rate);
63
58void w90x900_clk_enable(struct clk *clk, int enable) 64void w90x900_clk_enable(struct clk *clk, int enable)
59{ 65{
60 unsigned int clocks = clk->cken; 66 unsigned int clocks = clk->cken;
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
index bcc838f6b393..5e06770e6014 100644
--- a/arch/arm/mach-w90x900/time.c
+++ b/arch/arm/mach-w90x900/time.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks 4 * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks
5 * 5 *
6 * Copyright (c) 2008 Nuvoton technology corporation 6 * Copyright (c) 2009 Nuvoton technology corporation
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Wan ZongShun <mcuos.com@gmail.com> 9 * Wan ZongShun <mcuos.com@gmail.com>
@@ -23,6 +23,8 @@
23#include <linux/clk.h> 23#include <linux/clk.h>
24#include <linux/io.h> 24#include <linux/io.h>
25#include <linux/leds.h> 25#include <linux/leds.h>
26#include <linux/clocksource.h>
27#include <linux/clockchips.h>
26 28
27#include <asm/mach-types.h> 29#include <asm/mach-types.h>
28#include <asm/mach/irq.h> 30#include <asm/mach/irq.h>
@@ -31,49 +33,150 @@
31#include <mach/map.h> 33#include <mach/map.h>
32#include <mach/regs-timer.h> 34#include <mach/regs-timer.h>
33 35
34static unsigned long w90x900_gettimeoffset(void) 36#define RESETINT 0x1f
37#define PERIOD (0x01 << 27)
38#define ONESHOT (0x00 << 27)
39#define COUNTEN (0x01 << 30)
40#define INTEN (0x01 << 29)
41
42#define TICKS_PER_SEC 100
43#define PRESCALE 0x63 /* Divider = prescale + 1 */
44
45unsigned int timer0_load;
46
47static void w90p910_clockevent_setmode(enum clock_event_mode mode,
48 struct clock_event_device *clk)
35{ 49{
50 unsigned int val;
51
52 val = __raw_readl(REG_TCSR0);
53 val &= ~(0x03 << 27);
54
55 switch (mode) {
56 case CLOCK_EVT_MODE_PERIODIC:
57 __raw_writel(timer0_load, REG_TICR0);
58 val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
59 break;
60
61 case CLOCK_EVT_MODE_ONESHOT:
62 val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
63 break;
64
65 case CLOCK_EVT_MODE_UNUSED:
66 case CLOCK_EVT_MODE_SHUTDOWN:
67 case CLOCK_EVT_MODE_RESUME:
68 break;
69 }
70
71 __raw_writel(val, REG_TCSR0);
72}
73
74static int w90p910_clockevent_setnextevent(unsigned long evt,
75 struct clock_event_device *clk)
76{
77 unsigned int val;
78
79 __raw_writel(evt, REG_TICR0);
80
81 val = __raw_readl(REG_TCSR0);
82 val |= (COUNTEN | INTEN | PRESCALE);
83 __raw_writel(val, REG_TCSR0);
84
36 return 0; 85 return 0;
37} 86}
38 87
88static struct clock_event_device w90p910_clockevent_device = {
89 .name = "w90p910-timer0",
90 .shift = 32,
91 .features = CLOCK_EVT_MODE_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
92 .set_mode = w90p910_clockevent_setmode,
93 .set_next_event = w90p910_clockevent_setnextevent,
94 .rating = 300,
95};
96
39/*IRQ handler for the timer*/ 97/*IRQ handler for the timer*/
40 98
41static irqreturn_t 99static irqreturn_t w90p910_timer0_interrupt(int irq, void *dev_id)
42w90x900_timer_interrupt(int irq, void *dev_id)
43{ 100{
44 timer_tick(); 101 struct clock_event_device *evt = &w90p910_clockevent_device;
102
45 __raw_writel(0x01, REG_TISR); /* clear TIF0 */ 103 __raw_writel(0x01, REG_TISR); /* clear TIF0 */
104
105 evt->event_handler(evt);
46 return IRQ_HANDLED; 106 return IRQ_HANDLED;
47} 107}
48 108
49static struct irqaction w90x900_timer_irq = { 109static struct irqaction w90p910_timer0_irq = {
50 .name = "w90x900 Timer Tick", 110 .name = "w90p910-timer0",
51 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 111 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
52 .handler = w90x900_timer_interrupt, 112 .handler = w90p910_timer0_interrupt,
53}; 113};
54 114
55/*Set up timer reg.*/ 115static void __init w90p910_clockevents_init(unsigned int rate)
116{
117 w90p910_clockevent_device.mult = div_sc(rate, NSEC_PER_SEC,
118 w90p910_clockevent_device.shift);
119 w90p910_clockevent_device.max_delta_ns = clockevent_delta2ns(0xffffffff,
120 &w90p910_clockevent_device);
121 w90p910_clockevent_device.min_delta_ns = clockevent_delta2ns(0xf,
122 &w90p910_clockevent_device);
123 w90p910_clockevent_device.cpumask = cpumask_of(0);
56 124
57static void w90x900_timer_setup(void) 125 clockevents_register_device(&w90p910_clockevent_device);
126}
127
128static cycle_t w90p910_get_cycles(struct clocksource *cs)
58{ 129{
59 __raw_writel(0, REG_TCSR0); 130 return ~__raw_readl(REG_TDR1);
60 __raw_writel(0, REG_TCSR1);
61 __raw_writel(0, REG_TCSR2);
62 __raw_writel(0, REG_TCSR3);
63 __raw_writel(0, REG_TCSR4);
64 __raw_writel(0x1F, REG_TISR);
65 __raw_writel(15000000/(100 * 100), REG_TICR0);
66 __raw_writel(0x68000063, REG_TCSR0);
67} 131}
68 132
69static void __init w90x900_timer_init(void) 133static struct clocksource clocksource_w90p910 = {
134 .name = "w90p910-timer1",
135 .rating = 200,
136 .read = w90p910_get_cycles,
137 .mask = CLOCKSOURCE_MASK(32),
138 .shift = 20,
139 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
140};
141
142static void __init w90p910_clocksource_init(unsigned int rate)
70{ 143{
71 w90x900_timer_setup(); 144 unsigned int val;
72 setup_irq(IRQ_TIMER0, &w90x900_timer_irq); 145
146 __raw_writel(0xffffffff, REG_TICR1);
147
148 val = __raw_readl(REG_TCSR1);
149 val |= (COUNTEN | PERIOD);
150 __raw_writel(val, REG_TCSR1);
151
152 clocksource_w90p910.mult =
153 clocksource_khz2mult((rate / 1000), clocksource_w90p910.shift);
154 clocksource_register(&clocksource_w90p910);
155}
156
157static void __init w90p910_timer_init(void)
158{
159 struct clk *ck_ext = clk_get(NULL, "ext");
160 unsigned int rate;
161
162 BUG_ON(IS_ERR(ck_ext));
163
164 rate = clk_get_rate(ck_ext);
165 clk_put(ck_ext);
166 rate = rate / (PRESCALE + 0x01);
167
168 /* set a known state */
169 __raw_writel(0x00, REG_TCSR0);
170 __raw_writel(0x00, REG_TCSR1);
171 __raw_writel(RESETINT, REG_TISR);
172 timer0_load = (rate / TICKS_PER_SEC);
173
174 setup_irq(IRQ_TIMER0, &w90p910_timer0_irq);
175
176 w90p910_clocksource_init(rate);
177 w90p910_clockevents_init(rate);
73} 178}
74 179
75struct sys_timer w90x900_timer = { 180struct sys_timer w90x900_timer = {
76 .init = w90x900_timer_init, 181 .init = w90p910_timer_init,
77 .offset = w90x900_gettimeoffset,
78 .resume = w90x900_timer_setup
79}; 182};
diff --git a/arch/arm/mach-w90x900/w90p910.c b/arch/arm/mach-w90x900/w90p910.c
index 8444eababaab..d33723b69d14 100644
--- a/arch/arm/mach-w90x900/w90p910.c
+++ b/arch/arm/mach-w90x900/w90p910.c
@@ -76,6 +76,7 @@ static DEFINE_CLK(wdt, 26);
76static DEFINE_CLK(gdma, 27); 76static DEFINE_CLK(gdma, 27);
77static DEFINE_CLK(adc, 28); 77static DEFINE_CLK(adc, 28);
78static DEFINE_CLK(usi, 29); 78static DEFINE_CLK(usi, 29);
79static DEFINE_CLK(ext, 0);
79 80
80static struct clk_lookup w90p910_clkregs[] = { 81static struct clk_lookup w90p910_clkregs[] = {
81 DEF_CLKLOOK(&clk_lcd, "w90p910-lcd", NULL), 82 DEF_CLKLOOK(&clk_lcd, "w90p910-lcd", NULL),
@@ -97,6 +98,7 @@ static struct clk_lookup w90p910_clkregs[] = {
97 DEF_CLKLOOK(&clk_gdma, "w90p910-gdma", NULL), 98 DEF_CLKLOOK(&clk_gdma, "w90p910-gdma", NULL),
98 DEF_CLKLOOK(&clk_adc, "w90p910-adc", NULL), 99 DEF_CLKLOOK(&clk_adc, "w90p910-adc", NULL),
99 DEF_CLKLOOK(&clk_usi, "w90p910-spi", NULL), 100 DEF_CLKLOOK(&clk_usi, "w90p910-spi", NULL),
101 DEF_CLKLOOK(&clk_ext, NULL, "ext"),
100}; 102};
101 103
102/* Initial serial platform data */ 104/* Initial serial platform data */