aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ixp4xx/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ixp4xx/common.c')
-rw-r--r--arch/arm/mach-ixp4xx/common.c122
1 files changed, 100 insertions, 22 deletions
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 45068c3d8dcc..f5cae1e46b7e 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -27,6 +27,7 @@
27#include <linux/time.h> 27#include <linux/time.h>
28#include <linux/timex.h> 28#include <linux/timex.h>
29#include <linux/clocksource.h> 29#include <linux/clocksource.h>
30#include <linux/clockchips.h>
30 31
31#include <asm/arch/udc.h> 32#include <asm/arch/udc.h>
32#include <asm/hardware.h> 33#include <asm/hardware.h>
@@ -41,6 +42,8 @@
41#include <asm/mach/time.h> 42#include <asm/mach/time.h>
42 43
43static int __init ixp4xx_clocksource_init(void); 44static int __init ixp4xx_clocksource_init(void);
45static int __init ixp4xx_clockevent_init(void);
46static struct clock_event_device clockevent_ixp4xx;
44 47
45/************************************************************************* 48/*************************************************************************
46 * IXP4xx chipset I/O mapping 49 * IXP4xx chipset I/O mapping
@@ -102,6 +105,29 @@ static signed char irq2gpio[32] = {
102 7, 8, 9, 10, 11, 12, -1, -1, 105 7, 8, 9, 10, 11, 12, -1, -1,
103}; 106};
104 107
108int gpio_to_irq(int gpio)
109{
110 int irq;
111
112 for (irq = 0; irq < 32; irq++) {
113 if (irq2gpio[irq] == gpio)
114 return irq;
115 }
116 return -EINVAL;
117}
118EXPORT_SYMBOL(gpio_to_irq);
119
120int irq_to_gpio(int irq)
121{
122 int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL;
123
124 if (gpio == -1)
125 return -EINVAL;
126
127 return gpio;
128}
129EXPORT_SYMBOL(irq_to_gpio);
130
105static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) 131static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
106{ 132{
107 int line = irq2gpio[irq]; 133 int line = irq2gpio[irq];
@@ -169,7 +195,7 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
169 195
170static void ixp4xx_irq_mask(unsigned int irq) 196static void ixp4xx_irq_mask(unsigned int irq)
171{ 197{
172 if (cpu_is_ixp46x() && irq >= 32) 198 if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
173 *IXP4XX_ICMR2 &= ~(1 << (irq - 32)); 199 *IXP4XX_ICMR2 &= ~(1 << (irq - 32));
174 else 200 else
175 *IXP4XX_ICMR &= ~(1 << irq); 201 *IXP4XX_ICMR &= ~(1 << irq);
@@ -192,7 +218,7 @@ static void ixp4xx_irq_unmask(unsigned int irq)
192 if (!(ixp4xx_irq_edge & (1 << irq))) 218 if (!(ixp4xx_irq_edge & (1 << irq)))
193 ixp4xx_irq_ack(irq); 219 ixp4xx_irq_ack(irq);
194 220
195 if (cpu_is_ixp46x() && irq >= 32) 221 if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
196 *IXP4XX_ICMR2 |= (1 << (irq - 32)); 222 *IXP4XX_ICMR2 |= (1 << (irq - 32));
197 else 223 else
198 *IXP4XX_ICMR |= (1 << irq); 224 *IXP4XX_ICMR |= (1 << irq);
@@ -216,7 +242,7 @@ void __init ixp4xx_init_irq(void)
216 /* Disable all interrupt */ 242 /* Disable all interrupt */
217 *IXP4XX_ICMR = 0x0; 243 *IXP4XX_ICMR = 0x0;
218 244
219 if (cpu_is_ixp46x()) { 245 if (cpu_is_ixp46x() || cpu_is_ixp43x()) {
220 /* Route upper 32 sources to IRQ instead of FIQ */ 246 /* Route upper 32 sources to IRQ instead of FIQ */
221 *IXP4XX_ICLR2 = 0x00; 247 *IXP4XX_ICLR2 = 0x00;
222 248
@@ -239,52 +265,40 @@ void __init ixp4xx_init_irq(void)
239 * counter as a source of real clock ticks to account for missed jiffies. 265 * counter as a source of real clock ticks to account for missed jiffies.
240 *************************************************************************/ 266 *************************************************************************/
241 267
242static unsigned volatile last_jiffy_time;
243
244#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
245
246static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) 268static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
247{ 269{
248 write_seqlock(&xtime_lock); 270 struct clock_event_device *evt = &clockevent_ixp4xx;
249 271
250 /* Clear Pending Interrupt by writing '1' to it */ 272 /* Clear Pending Interrupt by writing '1' to it */
251 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; 273 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
252 274
253 /* 275 evt->event_handler(evt);
254 * Catch up with the real idea of time
255 */
256 while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
257 timer_tick();
258 last_jiffy_time += LATCH;
259 }
260
261 write_sequnlock(&xtime_lock);
262 276
263 return IRQ_HANDLED; 277 return IRQ_HANDLED;
264} 278}
265 279
266static struct irqaction ixp4xx_timer_irq = { 280static struct irqaction ixp4xx_timer_irq = {
267 .name = "IXP4xx Timer Tick", 281 .name = "timer1",
268 .flags = IRQF_DISABLED | IRQF_TIMER, 282 .flags = IRQF_DISABLED | IRQF_TIMER,
269 .handler = ixp4xx_timer_interrupt, 283 .handler = ixp4xx_timer_interrupt,
270}; 284};
271 285
272static void __init ixp4xx_timer_init(void) 286static void __init ixp4xx_timer_init(void)
273{ 287{
288 /* Reset/disable counter */
289 *IXP4XX_OSRT1 = 0;
290
274 /* Clear Pending Interrupt by writing '1' to it */ 291 /* Clear Pending Interrupt by writing '1' to it */
275 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; 292 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
276 293
277 /* Setup the Timer counter value */
278 *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
279
280 /* Reset time-stamp counter */ 294 /* Reset time-stamp counter */
281 *IXP4XX_OSTS = 0; 295 *IXP4XX_OSTS = 0;
282 last_jiffy_time = 0;
283 296
284 /* Connect the interrupt handler and enable the interrupt */ 297 /* Connect the interrupt handler and enable the interrupt */
285 setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); 298 setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
286 299
287 ixp4xx_clocksource_init(); 300 ixp4xx_clocksource_init();
301 ixp4xx_clockevent_init();
288} 302}
289 303
290struct sys_timer ixp4xx_timer = { 304struct sys_timer ixp4xx_timer = {
@@ -384,6 +398,9 @@ void __init ixp4xx_sys_init(void)
384 ixp4xx_exp_bus_size >> 20); 398 ixp4xx_exp_bus_size >> 20);
385} 399}
386 400
401/*
402 * clocksource
403 */
387cycle_t ixp4xx_get_cycles(void) 404cycle_t ixp4xx_get_cycles(void)
388{ 405{
389 return *IXP4XX_OSTS; 406 return *IXP4XX_OSTS;
@@ -408,3 +425,64 @@ static int __init ixp4xx_clocksource_init(void)
408 425
409 return 0; 426 return 0;
410} 427}
428
429/*
430 * clockevents
431 */
432static int ixp4xx_set_next_event(unsigned long evt,
433 struct clock_event_device *unused)
434{
435 unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
436
437 *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts;
438
439 return 0;
440}
441
442static void ixp4xx_set_mode(enum clock_event_mode mode,
443 struct clock_event_device *evt)
444{
445 unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
446
447 switch (mode) {
448 case CLOCK_EVT_MODE_PERIODIC:
449 osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK;
450 opts = IXP4XX_OST_ENABLE;
451 break;
452 case CLOCK_EVT_MODE_ONESHOT:
453 /* period set by 'set next_event' */
454 osrt = 0;
455 opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT;
456 break;
457 case CLOCK_EVT_MODE_SHUTDOWN:
458 case CLOCK_EVT_MODE_UNUSED:
459 default:
460 osrt = opts = 0;
461 break;
462 }
463
464 *IXP4XX_OSRT1 = osrt | opts;
465}
466
467static struct clock_event_device clockevent_ixp4xx = {
468 .name = "ixp4xx timer1",
469 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
470 .rating = 200,
471 .shift = 24,
472 .set_mode = ixp4xx_set_mode,
473 .set_next_event = ixp4xx_set_next_event,
474};
475
476static int __init ixp4xx_clockevent_init(void)
477{
478 clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
479 clockevent_ixp4xx.shift);
480 clockevent_ixp4xx.max_delta_ns =
481 clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
482 clockevent_ixp4xx.min_delta_ns =
483 clockevent_delta2ns(0xf, &clockevent_ixp4xx);
484 clockevent_ixp4xx.cpumask = cpumask_of_cpu(0);
485
486 clockevents_register_device(&clockevent_ixp4xx);
487 return 0;
488}