diff options
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r-- | arch/arm/mach-sa1100/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/gpio.c | 65 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/irq.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/time.c | 159 |
6 files changed, 134 insertions, 126 deletions
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 7a61e8d33ab7..8e0244631d65 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o | 6 | obj-y := clock.o generic.o gpio.o irq.o dma.o time.o #nmi-oopser.o |
7 | obj-m := | 7 | obj-m := |
8 | obj-n := | 8 | obj-n := |
9 | obj- := | 9 | obj- := |
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 5c84c604ed86..0c2fa1c4fb4c 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -139,37 +139,6 @@ unsigned long long sched_clock(void) | |||
139 | return v; | 139 | return v; |
140 | } | 140 | } |
141 | 141 | ||
142 | int gpio_direction_input(unsigned gpio) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | |||
146 | if (gpio > GPIO_MAX) | ||
147 | return -EINVAL; | ||
148 | |||
149 | local_irq_save(flags); | ||
150 | GPDR &= ~GPIO_GPIO(gpio); | ||
151 | local_irq_restore(flags); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | EXPORT_SYMBOL(gpio_direction_input); | ||
156 | |||
157 | int gpio_direction_output(unsigned gpio, int value) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | |||
161 | if (gpio > GPIO_MAX) | ||
162 | return -EINVAL; | ||
163 | |||
164 | local_irq_save(flags); | ||
165 | gpio_set_value(gpio, value); | ||
166 | GPDR |= GPIO_GPIO(gpio); | ||
167 | local_irq_restore(flags); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | EXPORT_SYMBOL(gpio_direction_output); | ||
172 | |||
173 | /* | 142 | /* |
174 | * Default power-off for SA1100 | 143 | * Default power-off for SA1100 |
175 | */ | 144 | */ |
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index f085d68e568e..793c2e6c991f 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h | |||
@@ -9,6 +9,7 @@ struct sys_timer; | |||
9 | extern struct sys_timer sa1100_timer; | 9 | extern struct sys_timer sa1100_timer; |
10 | extern void __init sa1100_map_io(void); | 10 | extern void __init sa1100_map_io(void); |
11 | extern void __init sa1100_init_irq(void); | 11 | extern void __init sa1100_init_irq(void); |
12 | extern void __init sa1100_init_gpio(void); | ||
12 | 13 | ||
13 | #define SET_BANK(__nr,__start,__size) \ | 14 | #define SET_BANK(__nr,__start,__size) \ |
14 | mi->bank[__nr].start = (__start), \ | 15 | mi->bank[__nr].start = (__start), \ |
diff --git a/arch/arm/mach-sa1100/gpio.c b/arch/arm/mach-sa1100/gpio.c new file mode 100644 index 000000000000..372f1f4f54a1 --- /dev/null +++ b/arch/arm/mach-sa1100/gpio.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-sa1100/gpio.c | ||
3 | * | ||
4 | * Generic SA-1100 GPIO handling | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include <asm/gpio.h> | ||
15 | #include <asm/hardware.h> | ||
16 | #include "generic.h" | ||
17 | |||
18 | static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
19 | { | ||
20 | return GPLR & GPIO_GPIO(offset); | ||
21 | } | ||
22 | |||
23 | static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
24 | { | ||
25 | if (value) | ||
26 | GPSR = GPIO_GPIO(offset); | ||
27 | else | ||
28 | GPCR = GPIO_GPIO(offset); | ||
29 | } | ||
30 | |||
31 | static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) | ||
32 | { | ||
33 | unsigned long flags; | ||
34 | |||
35 | local_irq_save(flags); | ||
36 | GPDR &= ~GPIO_GPIO(offset); | ||
37 | local_irq_restore(flags); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value) | ||
42 | { | ||
43 | unsigned long flags; | ||
44 | |||
45 | local_irq_save(flags); | ||
46 | sa1100_gpio_set(chip, offset, value); | ||
47 | GPDR |= GPIO_GPIO(offset); | ||
48 | local_irq_restore(flags); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static struct gpio_chip sa1100_gpio_chip = { | ||
53 | .label = "gpio", | ||
54 | .direction_input = sa1100_direction_input, | ||
55 | .direction_output = sa1100_direction_output, | ||
56 | .set = sa1100_gpio_set, | ||
57 | .get = sa1100_gpio_get, | ||
58 | .base = 0, | ||
59 | .ngpio = GPIO_MAX + 1, | ||
60 | }; | ||
61 | |||
62 | void __init sa1100_init_gpio(void) | ||
63 | { | ||
64 | gpiochip_add(&sa1100_gpio_chip); | ||
65 | } | ||
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 3dc17d7bf38e..fa0403af7eec 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c | |||
@@ -347,4 +347,6 @@ void __init sa1100_init_irq(void) | |||
347 | */ | 347 | */ |
348 | set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip); | 348 | set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip); |
349 | set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); | 349 | set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); |
350 | |||
351 | sa1100_init_gpio(); | ||
350 | } | 352 | } |
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index c2677368d6af..a9799cb35b74 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c | |||
@@ -13,67 +13,69 @@ | |||
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/timex.h> | 15 | #include <linux/timex.h> |
16 | #include <linux/signal.h> | 16 | #include <linux/clockchips.h> |
17 | #include <linux/clocksource.h> | ||
18 | 17 | ||
19 | #include <asm/mach/time.h> | 18 | #include <asm/mach/time.h> |
20 | #include <asm/hardware.h> | 19 | #include <asm/hardware.h> |
21 | 20 | ||
22 | #define RTC_DEF_DIVIDER (32768 - 1) | 21 | #define MIN_OSCR_DELTA 2 |
23 | #define RTC_DEF_TRIM 0 | ||
24 | 22 | ||
25 | static int sa1100_set_rtc(void) | 23 | static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id) |
26 | { | 24 | { |
27 | unsigned long current_time = xtime.tv_sec; | 25 | struct clock_event_device *c = dev_id; |
28 | 26 | ||
29 | if (RTSR & RTSR_ALE) { | 27 | /* Disarm the compare/match, signal the event. */ |
30 | /* make sure not to forward the clock over an alarm */ | 28 | OIER &= ~OIER_E0; |
31 | unsigned long alarm = RTAR; | 29 | OSSR = OSSR_M0; |
32 | if (current_time >= alarm && alarm >= RCNR) | 30 | c->event_handler(c); |
33 | return -ERESTARTSYS; | ||
34 | } | ||
35 | RCNR = current_time; | ||
36 | return 0; | ||
37 | } | ||
38 | 31 | ||
39 | #ifdef CONFIG_NO_IDLE_HZ | 32 | return IRQ_HANDLED; |
40 | static unsigned long initial_match; | 33 | } |
41 | static int match_posponed; | ||
42 | #endif | ||
43 | 34 | ||
44 | static irqreturn_t | 35 | static int |
45 | sa1100_timer_interrupt(int irq, void *dev_id) | 36 | sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c) |
46 | { | 37 | { |
47 | unsigned int next_match; | 38 | unsigned long flags, next, oscr; |
48 | 39 | ||
49 | #ifdef CONFIG_NO_IDLE_HZ | 40 | raw_local_irq_save(flags); |
50 | if (match_posponed) { | 41 | OIER |= OIER_E0; |
51 | match_posponed = 0; | 42 | next = OSCR + delta; |
52 | OSMR0 = initial_match; | 43 | OSMR0 = next; |
53 | } | 44 | oscr = OSCR; |
54 | #endif | 45 | raw_local_irq_restore(flags); |
55 | 46 | ||
56 | /* | 47 | return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; |
57 | * Loop until we get ahead of the free running timer. | 48 | } |
58 | * This ensures an exact clock tick count and time accuracy. | ||
59 | * Since IRQs are disabled at this point, coherence between | ||
60 | * lost_ticks(updated in do_timer()) and the match reg value is | ||
61 | * ensured, hence we can use do_gettimeofday() from interrupt | ||
62 | * handlers. | ||
63 | */ | ||
64 | do { | ||
65 | timer_tick(); | ||
66 | OSSR = OSSR_M0; /* Clear match on timer 0 */ | ||
67 | next_match = (OSMR0 += LATCH); | ||
68 | } while ((signed long)(next_match - OSCR) <= 0); | ||
69 | 49 | ||
70 | return IRQ_HANDLED; | 50 | static void |
51 | sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c) | ||
52 | { | ||
53 | unsigned long flags; | ||
54 | |||
55 | switch (mode) { | ||
56 | case CLOCK_EVT_MODE_ONESHOT: | ||
57 | case CLOCK_EVT_MODE_UNUSED: | ||
58 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
59 | raw_local_irq_save(flags); | ||
60 | OIER &= ~OIER_E0; | ||
61 | OSSR = OSSR_M0; | ||
62 | raw_local_irq_restore(flags); | ||
63 | break; | ||
64 | |||
65 | case CLOCK_EVT_MODE_RESUME: | ||
66 | case CLOCK_EVT_MODE_PERIODIC: | ||
67 | break; | ||
68 | } | ||
71 | } | 69 | } |
72 | 70 | ||
73 | static struct irqaction sa1100_timer_irq = { | 71 | static struct clock_event_device ckevt_sa1100_osmr0 = { |
74 | .name = "SA11xx Timer Tick", | 72 | .name = "osmr0", |
75 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 73 | .features = CLOCK_EVT_FEAT_ONESHOT, |
76 | .handler = sa1100_timer_interrupt, | 74 | .shift = 32, |
75 | .rating = 200, | ||
76 | .cpumask = CPU_MASK_CPU0, | ||
77 | .set_next_event = sa1100_osmr0_set_next_event, | ||
78 | .set_mode = sa1100_osmr0_set_mode, | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | static cycle_t sa1100_read_oscr(void) | 81 | static cycle_t sa1100_read_oscr(void) |
@@ -90,62 +92,34 @@ static struct clocksource cksrc_sa1100_oscr = { | |||
90 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 92 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
91 | }; | 93 | }; |
92 | 94 | ||
95 | static struct irqaction sa1100_timer_irq = { | ||
96 | .name = "ost0", | ||
97 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
98 | .handler = sa1100_ost0_interrupt, | ||
99 | .dev_id = &ckevt_sa1100_osmr0, | ||
100 | }; | ||
101 | |||
93 | static void __init sa1100_timer_init(void) | 102 | static void __init sa1100_timer_init(void) |
94 | { | 103 | { |
95 | unsigned long flags; | ||
96 | |||
97 | set_rtc = sa1100_set_rtc; | ||
98 | |||
99 | OIER = 0; /* disable any timer interrupts */ | 104 | OIER = 0; /* disable any timer interrupts */ |
100 | OSSR = 0xf; /* clear status on all timers */ | 105 | OSSR = 0xf; /* clear status on all timers */ |
101 | setup_irq(IRQ_OST0, &sa1100_timer_irq); | 106 | |
102 | local_irq_save(flags); | 107 | ckevt_sa1100_osmr0.mult = |
103 | OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ | 108 | div_sc(3686400, NSEC_PER_SEC, ckevt_sa1100_osmr0.shift); |
104 | OSMR0 = OSCR + LATCH; /* set initial match */ | 109 | ckevt_sa1100_osmr0.max_delta_ns = |
105 | local_irq_restore(flags); | 110 | clockevent_delta2ns(0x7fffffff, &ckevt_sa1100_osmr0); |
111 | ckevt_sa1100_osmr0.min_delta_ns = | ||
112 | clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_sa1100_osmr0) + 1; | ||
106 | 113 | ||
107 | cksrc_sa1100_oscr.mult = | 114 | cksrc_sa1100_oscr.mult = |
108 | clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_sa1100_oscr.shift); | 115 | clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_sa1100_oscr.shift); |
109 | 116 | ||
110 | clocksource_register(&cksrc_sa1100_oscr); | 117 | setup_irq(IRQ_OST0, &sa1100_timer_irq); |
111 | } | ||
112 | |||
113 | #ifdef CONFIG_NO_IDLE_HZ | ||
114 | static int sa1100_dyn_tick_enable_disable(void) | ||
115 | { | ||
116 | /* nothing to do */ | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static void sa1100_dyn_tick_reprogram(unsigned long ticks) | ||
121 | { | ||
122 | if (ticks > 1) { | ||
123 | initial_match = OSMR0; | ||
124 | OSMR0 = initial_match + ticks * LATCH; | ||
125 | match_posponed = 1; | ||
126 | } | ||
127 | } | ||
128 | 118 | ||
129 | static irqreturn_t | 119 | clocksource_register(&cksrc_sa1100_oscr); |
130 | sa1100_dyn_tick_handler(int irq, void *dev_id) | 120 | clockevents_register_device(&ckevt_sa1100_osmr0); |
131 | { | ||
132 | if (match_posponed) { | ||
133 | match_posponed = 0; | ||
134 | OSMR0 = initial_match; | ||
135 | if ((signed long)(initial_match - OSCR) <= 0) | ||
136 | return sa1100_timer_interrupt(irq, dev_id); | ||
137 | } | ||
138 | return IRQ_NONE; | ||
139 | } | 121 | } |
140 | 122 | ||
141 | static struct dyn_tick_timer sa1100_dyn_tick = { | ||
142 | .enable = sa1100_dyn_tick_enable_disable, | ||
143 | .disable = sa1100_dyn_tick_enable_disable, | ||
144 | .reprogram = sa1100_dyn_tick_reprogram, | ||
145 | .handler = sa1100_dyn_tick_handler, | ||
146 | }; | ||
147 | #endif | ||
148 | |||
149 | #ifdef CONFIG_PM | 123 | #ifdef CONFIG_PM |
150 | unsigned long osmr[4], oier; | 124 | unsigned long osmr[4], oier; |
151 | 125 | ||
@@ -181,7 +155,4 @@ struct sys_timer sa1100_timer = { | |||
181 | .init = sa1100_timer_init, | 155 | .init = sa1100_timer_init, |
182 | .suspend = sa1100_timer_suspend, | 156 | .suspend = sa1100_timer_suspend, |
183 | .resume = sa1100_timer_resume, | 157 | .resume = sa1100_timer_resume, |
184 | #ifdef CONFIG_NO_IDLE_HZ | ||
185 | .dyn_tick = &sa1100_dyn_tick, | ||
186 | #endif | ||
187 | }; | 158 | }; |