aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sa1100
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r--arch/arm/mach-sa1100/Makefile2
-rw-r--r--arch/arm/mach-sa1100/generic.c31
-rw-r--r--arch/arm/mach-sa1100/generic.h1
-rw-r--r--arch/arm/mach-sa1100/gpio.c65
-rw-r--r--arch/arm/mach-sa1100/irq.c2
-rw-r--r--arch/arm/mach-sa1100/time.c159
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
6obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o 6obj-y := clock.o generic.o gpio.o irq.o dma.o time.o #nmi-oopser.o
7obj-m := 7obj-m :=
8obj-n := 8obj-n :=
9obj- := 9obj- :=
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
142int 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
155EXPORT_SYMBOL(gpio_direction_input);
156
157int 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
171EXPORT_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;
9extern struct sys_timer sa1100_timer; 9extern struct sys_timer sa1100_timer;
10extern void __init sa1100_map_io(void); 10extern void __init sa1100_map_io(void);
11extern void __init sa1100_init_irq(void); 11extern void __init sa1100_init_irq(void);
12extern 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
18static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
19{
20 return GPLR & GPIO_GPIO(offset);
21}
22
23static 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
31static 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
41static 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
52static 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
62void __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
25static int sa1100_set_rtc(void) 23static 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;
40static unsigned long initial_match; 33}
41static int match_posponed;
42#endif
43 34
44static irqreturn_t 35static int
45sa1100_timer_interrupt(int irq, void *dev_id) 36sa1100_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; 50static void
51sa1100_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
73static struct irqaction sa1100_timer_irq = { 71static 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
79static cycle_t sa1100_read_oscr(void) 81static 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
95static 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
93static void __init sa1100_timer_init(void) 102static 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
114static int sa1100_dyn_tick_enable_disable(void)
115{
116 /* nothing to do */
117 return 0;
118}
119
120static 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
129static irqreturn_t 119 clocksource_register(&cksrc_sa1100_oscr);
130sa1100_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
141static 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
150unsigned long osmr[4], oier; 124unsigned 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};