aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ns9xxx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r--arch/arm/mach-ns9xxx/Makefile2
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.c70
-rw-r--r--arch/arm/mach-ns9xxx/gpio.c190
-rw-r--r--arch/arm/mach-ns9xxx/irq.c50
-rw-r--r--arch/arm/mach-ns9xxx/time.c172
5 files changed, 380 insertions, 104 deletions
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
index 4476411b8140..6fb82b855a55 100644
--- a/arch/arm/mach-ns9xxx/Makefile
+++ b/arch/arm/mach-ns9xxx/Makefile
@@ -1,4 +1,4 @@
1obj-y := irq.o time.o generic.o 1obj-y := irq.o time.o generic.o gpio.o
2 2
3obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o 3obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
4obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o 4obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
index 925048e7adfe..0f65177f9e5f 100644
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
@@ -13,6 +13,7 @@
13#include <linux/irq.h> 13#include <linux/irq.h>
14 14
15#include <asm/mach/map.h> 15#include <asm/mach/map.h>
16#include <asm/gpio.h>
16 17
17#include <asm/arch-ns9xxx/board.h> 18#include <asm/arch-ns9xxx/board.h>
18#include <asm/arch-ns9xxx/regs-sys.h> 19#include <asm/arch-ns9xxx/regs-sys.h>
@@ -44,7 +45,13 @@ static void a9m9750dev_fpga_ack_irq(unsigned int irq)
44 45
45static void a9m9750dev_fpga_mask_irq(unsigned int irq) 46static void a9m9750dev_fpga_mask_irq(unsigned int irq)
46{ 47{
47 FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0))); 48 u8 ier;
49
50 ier = __raw_readb(FPGA_IER);
51
52 ier &= ~(1 << (irq - FPGA_IRQ(0)));
53
54 __raw_writeb(ier, FPGA_IER);
48} 55}
49 56
50static void a9m9750dev_fpga_maskack_irq(unsigned int irq) 57static void a9m9750dev_fpga_maskack_irq(unsigned int irq)
@@ -55,7 +62,13 @@ static void a9m9750dev_fpga_maskack_irq(unsigned int irq)
55 62
56static void a9m9750dev_fpga_unmask_irq(unsigned int irq) 63static void a9m9750dev_fpga_unmask_irq(unsigned int irq)
57{ 64{
58 FPGA_IER |= 1 << (irq - FPGA_IRQ(0)); 65 u8 ier;
66
67 ier = __raw_readb(FPGA_IER);
68
69 ier |= 1 << (irq - FPGA_IRQ(0));
70
71 __raw_writeb(ier, FPGA_IER);
59} 72}
60 73
61static struct irq_chip a9m9750dev_fpga_chip = { 74static struct irq_chip a9m9750dev_fpga_chip = {
@@ -68,30 +81,34 @@ static struct irq_chip a9m9750dev_fpga_chip = {
68static void a9m9750dev_fpga_demux_handler(unsigned int irq, 81static void a9m9750dev_fpga_demux_handler(unsigned int irq,
69 struct irq_desc *desc) 82 struct irq_desc *desc)
70{ 83{
71 int stat = FPGA_ISR; 84 u8 stat = __raw_readb(FPGA_ISR);
85
86 desc->chip->mask_ack(irq);
72 87
73 while (stat != 0) { 88 while (stat != 0) {
74 int irqno = fls(stat) - 1; 89 int irqno = fls(stat) - 1;
90 struct irq_desc *fpgadesc;
75 91
76 stat &= ~(1 << irqno); 92 stat &= ~(1 << irqno);
77 93
78 desc = irq_desc + FPGA_IRQ(irqno); 94 fpgadesc = irq_desc + FPGA_IRQ(irqno);
79 95
80 desc_handle_irq(FPGA_IRQ(irqno), desc); 96 desc_handle_irq(FPGA_IRQ(irqno), fpgadesc);
81 } 97 }
98
99 desc->chip->unmask(irq);
82} 100}
83 101
84void __init board_a9m9750dev_init_irq(void) 102void __init board_a9m9750dev_init_irq(void)
85{ 103{
86 u32 reg; 104 u32 eic;
87 int i; 105 int i;
88 106
89 /* 107 if (gpio_request(11, "board a9m9750dev extirq2") == 0)
90 * configure gpio for IRQ_EXT2 108 ns9xxx_gpio_configure(11, 0, 1);
91 * use GPIO 11, because GPIO 32 is used for the LCD 109 else
92 */ 110 printk(KERN_ERR "%s: cannot get gpio 11 for IRQ_EXT2\n",
93 /* XXX: proper GPIO handling */ 111 __func__);
94 BBU_GCONFb1(1) &= ~0x2000;
95 112
96 for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { 113 for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) {
97 set_irq_chip(i, &a9m9750dev_fpga_chip); 114 set_irq_chip(i, &a9m9750dev_fpga_chip);
@@ -100,10 +117,10 @@ void __init board_a9m9750dev_init_irq(void)
100 } 117 }
101 118
102 /* IRQ_EXT2: level sensitive + active low */ 119 /* IRQ_EXT2: level sensitive + active low */
103 reg = SYS_EIC(2); 120 eic = __raw_readl(SYS_EIC(2));
104 REGSET(reg, SYS_EIC, PLTY, AL); 121 REGSET(eic, SYS_EIC, PLTY, AL);
105 REGSET(reg, SYS_EIC, LVEDG, LEVEL); 122 REGSET(eic, SYS_EIC, LVEDG, LEVEL);
106 SYS_EIC(2) = reg; 123 __raw_writel(eic, SYS_EIC(2));
107 124
108 set_irq_chained_handler(IRQ_EXT2, 125 set_irq_chained_handler(IRQ_EXT2,
109 a9m9750dev_fpga_demux_handler); 126 a9m9750dev_fpga_demux_handler);
@@ -167,17 +184,18 @@ void __init board_a9m9750dev_init_machine(void)
167 u32 reg; 184 u32 reg;
168 185
169 /* setup static CS0: memory base ... */ 186 /* setup static CS0: memory base ... */
170 REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB, 187 reg = __raw_readl(SYS_SMCSSMB(0));
171 NS9XXX_CSxSTAT_PHYS(0) >> 12); 188 REGSETIM(reg, SYS_SMCSSMB, CSxB, NS9XXX_CSxSTAT_PHYS(0) >> 12);
189 __raw_writel(reg, SYS_SMCSSMB(0));
172 190
173 /* ... and mask */ 191 /* ... and mask */
174 reg = SYS_SMCSSMM(0); 192 reg = __raw_readl(SYS_SMCSSMM(0));
175 REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); 193 REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff);
176 REGSET(reg, SYS_SMCSSMM, CSEx, EN); 194 REGSET(reg, SYS_SMCSSMM, CSEx, EN);
177 SYS_SMCSSMM(0) = reg; 195 __raw_writel(reg, SYS_SMCSSMM(0));
178 196
179 /* setup static CS0: memory configuration */ 197 /* setup static CS0: memory configuration */
180 reg = MEM_SMC(0); 198 reg = __raw_readl(MEM_SMC(0));
181 REGSET(reg, MEM_SMC, PSMC, OFF); 199 REGSET(reg, MEM_SMC, PSMC, OFF);
182 REGSET(reg, MEM_SMC, BSMC, OFF); 200 REGSET(reg, MEM_SMC, BSMC, OFF);
183 REGSET(reg, MEM_SMC, EW, OFF); 201 REGSET(reg, MEM_SMC, EW, OFF);
@@ -185,13 +203,13 @@ void __init board_a9m9750dev_init_machine(void)
185 REGSET(reg, MEM_SMC, PC, AL); 203 REGSET(reg, MEM_SMC, PC, AL);
186 REGSET(reg, MEM_SMC, PM, DIS); 204 REGSET(reg, MEM_SMC, PM, DIS);
187 REGSET(reg, MEM_SMC, MW, 8); 205 REGSET(reg, MEM_SMC, MW, 8);
188 MEM_SMC(0) = reg; 206 __raw_writel(reg, MEM_SMC(0));
189 207
190 /* setup static CS0: timing */ 208 /* setup static CS0: timing */
191 MEM_SMWED(0) = 0x2; 209 __raw_writel(0x2, MEM_SMWED(0));
192 MEM_SMOED(0) = 0x2; 210 __raw_writel(0x2, MEM_SMOED(0));
193 MEM_SMRD(0) = 0x6; 211 __raw_writel(0x6, MEM_SMRD(0));
194 MEM_SMWD(0) = 0x6; 212 __raw_writel(0x6, MEM_SMWD(0));
195 213
196 platform_add_devices(board_a9m9750dev_devices, 214 platform_add_devices(board_a9m9750dev_devices,
197 ARRAY_SIZE(board_a9m9750dev_devices)); 215 ARRAY_SIZE(board_a9m9750dev_devices));
diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c
new file mode 100644
index 000000000000..b2230213b983
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/gpio.c
@@ -0,0 +1,190 @@
1/*
2 * arch/arm/mach-ns9xxx/gpio.c
3 *
4 * Copyright (C) 2006 by Digi International Inc.
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11#include <linux/compiler.h>
12#include <linux/init.h>
13#include <linux/spinlock.h>
14#include <linux/module.h>
15
16#include <asm/arch-ns9xxx/gpio.h>
17#include <asm/arch-ns9xxx/processor.h>
18#include <asm/arch-ns9xxx/regs-bbu.h>
19#include <asm/io.h>
20#include <asm/bug.h>
21#include <asm/types.h>
22#include <asm/bitops.h>
23
24#if defined(CONFIG_PROCESSOR_NS9360)
25#define GPIO_MAX 72
26#elif defined(CONFIG_PROCESSOR_NS9750)
27#define GPIO_MAX 49
28#endif
29
30/* protects BBU_GCONFx and BBU_GCTRLx */
31static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
32
33/* only access gpiores with atomic ops */
34static DECLARE_BITMAP(gpiores, GPIO_MAX);
35
36static inline int ns9xxx_valid_gpio(unsigned gpio)
37{
38#if defined(CONFIG_PROCESSOR_NS9360)
39 if (processor_is_ns9360())
40 return gpio <= 72;
41 else
42#endif
43#if defined(CONFIG_PROCESSOR_NS9750)
44 if (processor_is_ns9750())
45 return gpio <= 49;
46 else
47#endif
48 BUG();
49}
50
51static inline void __iomem *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
52{
53 if (gpio < 56)
54 return BBU_GCONFb1(gpio / 8);
55 else
56 /*
57 * this could be optimised away on
58 * ns9750 only builds, but it isn't ...
59 */
60 return BBU_GCONFb2((gpio - 56) / 8);
61}
62
63static inline void __iomem *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
64{
65 if (gpio < 32)
66 return BBU_GCTRL1;
67 else if (gpio < 64)
68 return BBU_GCTRL2;
69 else
70 /* this could be optimised away on ns9750 only builds */
71 return BBU_GCTRL3;
72}
73
74static inline void __iomem *ns9xxx_gpio_get_gstataddr(unsigned gpio)
75{
76 if (gpio < 32)
77 return BBU_GSTAT1;
78 else if (gpio < 64)
79 return BBU_GSTAT2;
80 else
81 /* this could be optimised away on ns9750 only builds */
82 return BBU_GSTAT3;
83}
84
85int gpio_request(unsigned gpio, const char *label)
86{
87 if (likely(ns9xxx_valid_gpio(gpio)))
88 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
89 else
90 return -EINVAL;
91}
92EXPORT_SYMBOL(gpio_request);
93
94void gpio_free(unsigned gpio)
95{
96 clear_bit(gpio, gpiores);
97 return;
98}
99EXPORT_SYMBOL(gpio_free);
100
101/*
102 * each gpio can serve for 4 different purposes [0..3]. These are called
103 * "functions" and passed in the parameter func. Functions 0-2 are always some
104 * special things, function 3 is GPIO. If func == 3 dir specifies input or
105 * output, and with inv you can enable an inverter (independent of func).
106 */
107static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
108{
109 void __iomem *conf = ns9xxx_gpio_get_gconfaddr(gpio);
110 u32 confval;
111 unsigned long flags;
112
113 spin_lock_irqsave(&gpio_lock, flags);
114
115 confval = __raw_readl(conf);
116 REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
117 REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
118 REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
119 __raw_writel(confval, conf);
120
121 spin_unlock_irqrestore(&gpio_lock, flags);
122
123 return 0;
124}
125
126int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
127{
128 if (likely(ns9xxx_valid_gpio(gpio))) {
129 if (func == 3) {
130 printk(KERN_WARNING "use gpio_direction_input "
131 "or gpio_direction_output\n");
132 return -EINVAL;
133 } else
134 return __ns9xxx_gpio_configure(gpio, 0, inv, func);
135 } else
136 return -EINVAL;
137}
138EXPORT_SYMBOL(ns9xxx_gpio_configure);
139
140int gpio_direction_input(unsigned gpio)
141{
142 if (likely(ns9xxx_valid_gpio(gpio))) {
143 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
144 } else
145 return -EINVAL;
146}
147EXPORT_SYMBOL(gpio_direction_input);
148
149int gpio_direction_output(unsigned gpio, int value)
150{
151 if (likely(ns9xxx_valid_gpio(gpio))) {
152 gpio_set_value(gpio, value);
153
154 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
155 } else
156 return -EINVAL;
157}
158EXPORT_SYMBOL(gpio_direction_output);
159
160int gpio_get_value(unsigned gpio)
161{
162 void __iomem *stat = ns9xxx_gpio_get_gstataddr(gpio);
163 int ret;
164
165 ret = 1 & (__raw_readl(stat) >> (gpio & 31));
166
167 return ret;
168}
169EXPORT_SYMBOL(gpio_get_value);
170
171void gpio_set_value(unsigned gpio, int value)
172{
173 void __iomem *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
174 u32 ctrlval;
175 unsigned long flags;
176
177 spin_lock_irqsave(&gpio_lock, flags);
178
179 ctrlval = __raw_readl(ctrl);
180
181 if (value)
182 ctrlval |= 1 << (gpio & 31);
183 else
184 ctrlval &= ~(1 << (gpio & 31));
185
186 __raw_writel(ctrlval, ctrl);
187
188 spin_unlock_irqrestore(&gpio_lock, flags);
189}
190EXPORT_SYMBOL(gpio_set_value);
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
index b8c7b00522e6..00001b874e97 100644
--- a/arch/arm/mach-ns9xxx/irq.c
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -9,6 +9,7 @@
9 * the Free Software Foundation. 9 * the Free Software Foundation.
10 */ 10 */
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <asm/io.h>
12#include <asm/mach/irq.h> 13#include <asm/mach/irq.h>
13#include <asm/mach-types.h> 14#include <asm/mach-types.h>
14#include <asm/arch-ns9xxx/regs-sys.h> 15#include <asm/arch-ns9xxx/regs-sys.h>
@@ -17,48 +18,17 @@
17 18
18#include "generic.h" 19#include "generic.h"
19 20
20static void ns9xxx_ack_irq_timer(unsigned int irq)
21{
22 u32 tc = SYS_TC(irq - IRQ_TIMER0);
23
24 /*
25 * If the timer is programmed to halt on terminal count, the
26 * timer must be disabled before clearing the interrupt.
27 */
28 if (REGGET(tc, SYS_TCx, REN) == 0) {
29 REGSET(tc, SYS_TCx, TEN, DIS);
30 SYS_TC(irq - IRQ_TIMER0) = tc;
31 }
32
33 REGSET(tc, SYS_TCx, INTC, SET);
34 SYS_TC(irq - IRQ_TIMER0) = tc;
35
36 REGSET(tc, SYS_TCx, INTC, UNSET);
37 SYS_TC(irq - IRQ_TIMER0) = tc;
38}
39
40static void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
41 [IRQ_TIMER0] = ns9xxx_ack_irq_timer,
42 [IRQ_TIMER1] = ns9xxx_ack_irq_timer,
43 [IRQ_TIMER2] = ns9xxx_ack_irq_timer,
44 [IRQ_TIMER3] = ns9xxx_ack_irq_timer,
45};
46
47static void ns9xxx_mask_irq(unsigned int irq) 21static void ns9xxx_mask_irq(unsigned int irq)
48{ 22{
49 /* XXX: better use cpp symbols */ 23 /* XXX: better use cpp symbols */
50 SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3)))); 24 u32 ic = __raw_readl(SYS_IC(irq / 4));
25 ic &= ~(1 << (7 + 8 * (3 - (irq & 3))));
26 __raw_writel(ic, SYS_IC(irq / 4));
51} 27}
52 28
53static void ns9xxx_ack_irq(unsigned int irq) 29static void ns9xxx_ack_irq(unsigned int irq)
54{ 30{
55 if (!ns9xxx_ack_irq_functions[irq]) { 31 __raw_writel(0, SYS_ISRADDR);
56 printk(KERN_ERR "no ack function for irq %u\n", irq);
57 BUG();
58 }
59
60 ns9xxx_ack_irq_functions[irq](irq);
61 SYS_ISRADDR = 0;
62} 32}
63 33
64static void ns9xxx_maskack_irq(unsigned int irq) 34static void ns9xxx_maskack_irq(unsigned int irq)
@@ -70,7 +40,9 @@ static void ns9xxx_maskack_irq(unsigned int irq)
70static void ns9xxx_unmask_irq(unsigned int irq) 40static void ns9xxx_unmask_irq(unsigned int irq)
71{ 41{
72 /* XXX: better use cpp symbols */ 42 /* XXX: better use cpp symbols */
73 SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3))); 43 u32 ic = __raw_readl(SYS_IC(irq / 4));
44 ic |= 1 << (7 + 8 * (3 - (irq & 3)));
45 __raw_writel(ic, SYS_IC(irq / 4));
74} 46}
75 47
76static struct irq_chip ns9xxx_chip = { 48static struct irq_chip ns9xxx_chip = {
@@ -86,14 +58,14 @@ void __init ns9xxx_init_irq(void)
86 58
87 /* disable all IRQs */ 59 /* disable all IRQs */
88 for (i = 0; i < 8; ++i) 60 for (i = 0; i < 8; ++i)
89 SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 | 61 __raw_writel((4 * i) << 24 | (4 * i + 1) << 16 |
90 (4 * i + 2) << 8 | (4 * i + 3); 62 (4 * i + 2) << 8 | (4 * i + 3), SYS_IC(i));
91 63
92 /* simple interrupt prio table: 64 /* simple interrupt prio table:
93 * prio(x) < prio(y) <=> x < y 65 * prio(x) < prio(y) <=> x < y
94 */ 66 */
95 for (i = 0; i < 32; ++i) 67 for (i = 0; i < 32; ++i)
96 SYS_IVA(i) = i; 68 __raw_writel(i, SYS_IVA(i));
97 69
98 for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { 70 for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) {
99 set_irq_chip(i, &ns9xxx_chip); 71 set_irq_chip(i, &ns9xxx_chip);
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
index b97d0c54a388..c3dd1f4acb99 100644
--- a/arch/arm/mach-ns9xxx/time.c
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -11,78 +11,174 @@
11#include <linux/jiffies.h> 11#include <linux/jiffies.h>
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/stringify.h>
15#include <linux/clocksource.h>
16#include <linux/clockchips.h>
17
14#include <asm/arch-ns9xxx/regs-sys.h> 18#include <asm/arch-ns9xxx/regs-sys.h>
15#include <asm/arch-ns9xxx/clock.h> 19#include <asm/arch-ns9xxx/clock.h>
16#include <asm/arch-ns9xxx/irqs.h> 20#include <asm/arch-ns9xxx/irqs.h>
17#include <asm/arch/system.h> 21#include <asm/arch/system.h>
18#include "generic.h" 22#include "generic.h"
19 23
20#define TIMERCLOCKSELECT 64 24#define TIMER_CLOCKSOURCE 0
25#define TIMER_CLOCKEVENT 1
26static u32 latch;
27
28static cycle_t ns9xxx_clocksource_read(void)
29{
30 return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE));
31}
21 32
22static u32 usecs_per_tick; 33static struct clocksource ns9xxx_clocksource = {
34 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE),
35 .rating = 300,
36 .read = ns9xxx_clocksource_read,
37 .mask = CLOCKSOURCE_MASK(32),
38 .shift = 20,
39 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
40};
23 41
24static irqreturn_t 42static void ns9xxx_clockevent_setmode(enum clock_event_mode mode,
25ns9xxx_timer_interrupt(int irq, void *dev_id) 43 struct clock_event_device *clk)
26{ 44{
27 write_seqlock(&xtime_lock); 45 u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
28 timer_tick(); 46
29 write_sequnlock(&xtime_lock); 47 switch(mode) {
48 case CLOCK_EVT_MODE_PERIODIC:
49 __raw_writel(latch, SYS_TRC(TIMER_CLOCKEVENT));
50 REGSET(tc, SYS_TCx, REN, EN);
51 REGSET(tc, SYS_TCx, INTS, EN);
52 REGSET(tc, SYS_TCx, TEN, EN);
53 break;
54
55 case CLOCK_EVT_MODE_ONESHOT:
56 REGSET(tc, SYS_TCx, REN, DIS);
57 REGSET(tc, SYS_TCx, INTS, EN);
58
59 /* fall through */
60
61 case CLOCK_EVT_MODE_UNUSED:
62 case CLOCK_EVT_MODE_SHUTDOWN:
63 case CLOCK_EVT_MODE_RESUME:
64 default:
65 REGSET(tc, SYS_TCx, TEN, DIS);
66 break;
67 }
68
69 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
70}
30 71
31 return IRQ_HANDLED; 72static int ns9xxx_clockevent_setnextevent(unsigned long evt,
73 struct clock_event_device *clk)
74{
75 u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
76
77 if (REGGET(tc, SYS_TCx, TEN)) {
78 REGSET(tc, SYS_TCx, TEN, DIS);
79 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
80 }
81
82 REGSET(tc, SYS_TCx, TEN, EN);
83
84 __raw_writel(evt, SYS_TRC(TIMER_CLOCKEVENT));
85
86 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
87
88 return 0;
32} 89}
33 90
34static unsigned long ns9xxx_timer_gettimeoffset(void) 91static struct clock_event_device ns9xxx_clockevent_device = {
92 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT),
93 .shift = 20,
94 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
95 .set_mode = ns9xxx_clockevent_setmode,
96 .set_next_event = ns9xxx_clockevent_setnextevent,
97};
98
99static irqreturn_t ns9xxx_clockevent_handler(int irq, void *dev_id)
35{ 100{
36 /* return the microseconds which have passed since the last interrupt 101 int timerno = irq - IRQ_TIMER0;
37 * was _serviced_. That is, if an interrupt is pending or the counter 102 u32 tc;
38 * reloads, return one period more. */
39 103
40 u32 counter1 = SYS_TR(0); 104 struct clock_event_device *evt = &ns9xxx_clockevent_device;
41 int pending = SYS_ISR & (1 << IRQ_TIMER0);
42 u32 counter2 = SYS_TR(0);
43 u32 elapsed;
44 105
45 if (pending || counter2 > counter1) 106 /* clear irq */
46 elapsed = 2 * SYS_TRC(0) - counter2; 107 tc = __raw_readl(SYS_TC(timerno));
47 else 108 if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) {
48 elapsed = SYS_TRC(0) - counter1; 109 REGSET(tc, SYS_TCx, TEN, DIS);
110 __raw_writel(tc, SYS_TC(timerno));
111 }
112 REGSET(tc, SYS_TCx, INTC, SET);
113 __raw_writel(tc, SYS_TC(timerno));
114 REGSET(tc, SYS_TCx, INTC, UNSET);
115 __raw_writel(tc, SYS_TC(timerno));
49 116
50 return (elapsed * usecs_per_tick) >> 16; 117 evt->event_handler(evt);
51 118
119 return IRQ_HANDLED;
52} 120}
53 121
54static struct irqaction ns9xxx_timer_irq = { 122static struct irqaction ns9xxx_clockevent_action = {
55 .name = "NS9xxx Timer Tick", 123 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT),
56 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 124 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
57 .handler = ns9xxx_timer_interrupt, 125 .handler = ns9xxx_clockevent_handler,
58}; 126};
59 127
60static void __init ns9xxx_timer_init(void) 128static void __init ns9xxx_timer_init(void)
61{ 129{
62 int tc; 130 int tc;
63 131
64 usecs_per_tick = 132 tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE));
65 SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); 133 if (REGGET(tc, SYS_TCx, TEN)) {
134 REGSET(tc, SYS_TCx, TEN, DIS);
135 __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
136 }
66 137
67 /* disable timer */ 138 __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE));
68 if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
69 SYS_TC(0) = tc & ~SYS_TCx_TEN;
70
71 SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
72 139
73 REGSET(tc, SYS_TCx, TEN, EN); 140 REGSET(tc, SYS_TCx, TEN, EN);
74 REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
75 REGSET(tc, SYS_TCx, INTS, EN);
76 REGSET(tc, SYS_TCx, UDS, DOWN);
77 REGSET(tc, SYS_TCx, TDBG, STOP); 141 REGSET(tc, SYS_TCx, TDBG, STOP);
142 REGSET(tc, SYS_TCx, TLCS, CPU);
143 REGSET(tc, SYS_TCx, TM, IEE);
144 REGSET(tc, SYS_TCx, INTS, DIS);
145 REGSET(tc, SYS_TCx, UDS, UP);
78 REGSET(tc, SYS_TCx, TSZ, 32); 146 REGSET(tc, SYS_TCx, TSZ, 32);
79 REGSET(tc, SYS_TCx, REN, EN); 147 REGSET(tc, SYS_TCx, REN, EN);
80 SYS_TC(0) = tc;
81 148
82 setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); 149 __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
150
151 ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(),
152 ns9xxx_clocksource.shift);
153
154 clocksource_register(&ns9xxx_clocksource);
155
156 latch = SH_DIV(ns9xxx_cpuclock(), HZ, 0);
157
158 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
159 REGSET(tc, SYS_TCx, TEN, DIS);
160 REGSET(tc, SYS_TCx, TDBG, STOP);
161 REGSET(tc, SYS_TCx, TLCS, CPU);
162 REGSET(tc, SYS_TCx, TM, IEE);
163 REGSET(tc, SYS_TCx, INTS, DIS);
164 REGSET(tc, SYS_TCx, UDS, DOWN);
165 REGSET(tc, SYS_TCx, TSZ, 32);
166 REGSET(tc, SYS_TCx, REN, EN);
167 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
168
169 ns9xxx_clockevent_device.mult = div_sc(ns9xxx_cpuclock(),
170 NSEC_PER_SEC, ns9xxx_clockevent_device.shift);
171 ns9xxx_clockevent_device.max_delta_ns =
172 clockevent_delta2ns(-1, &ns9xxx_clockevent_device);
173 ns9xxx_clockevent_device.min_delta_ns =
174 clockevent_delta2ns(1, &ns9xxx_clockevent_device);
175
176 ns9xxx_clockevent_device.cpumask = cpumask_of_cpu(0);
177 clockevents_register_device(&ns9xxx_clockevent_device);
178
179 setup_irq(IRQ_TIMER0 + TIMER_CLOCKEVENT, &ns9xxx_clockevent_action);
83} 180}
84 181
85struct sys_timer ns9xxx_timer = { 182struct sys_timer ns9xxx_timer = {
86 .init = ns9xxx_timer_init, 183 .init = ns9xxx_timer_init,
87 .offset = ns9xxx_timer_gettimeoffset,
88}; 184};