Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
[pandora-kernel.git] / arch / arm / mach-integrator / integrator_ap.c
index b19ae18..a1769f3 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mtd/physmap.h>
+#include <linux/clk.h>
+#include <video/vga.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
@@ -154,6 +156,7 @@ static struct map_desc ap_io_desc[] __initdata = {
 static void __init ap_map_io(void)
 {
        iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
+       vga_base = PCI_MEMORY_VADDR;
 }
 
 #define INTEGRATOR_SC_VALID_INT        0x003fffff
@@ -320,27 +323,16 @@ static void __init ap_init(void)
 #define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
 #define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
 
-/*
- * How long is the timer interval?
- */
-#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
-#else
-#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
-#endif
-
 static unsigned long timer_reload;
 
-static void integrator_clocksource_init(u32 khz)
+static void integrator_clocksource_init(unsigned long inrate)
 {
        void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
        u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+       unsigned long rate = inrate;
 
-       if (khz >= 1500) {
-               khz /= 16;
+       if (rate >= 1500000) {
+               rate /= 16;
                ctrl |= TIMER_CTRL_DIV16;
        }
 
@@ -348,7 +340,7 @@ static void integrator_clocksource_init(u32 khz)
        writel(ctrl, base + TIMER_CTRL);
 
        clocksource_mmio_init(base + TIMER_VALUE, "timer2",
-               khz * 1000, 200, 16, clocksource_mmio_readl_down);
+                       rate, 200, 16, clocksource_mmio_readl_down);
 }
 
 static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
@@ -372,15 +364,29 @@ static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_devic
 {
        u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
 
-       BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT);
+       /* Disable timer */
+       writel(ctrl, clkevt_base + TIMER_CTRL);
 
-       if (mode == CLOCK_EVT_MODE_PERIODIC) {
-               writel(ctrl, clkevt_base + TIMER_CTRL);
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* Enable the timer and start the periodic tick */
                writel(timer_reload, clkevt_base + TIMER_LOAD);
                ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+               writel(ctrl, clkevt_base + TIMER_CTRL);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* Leave the timer disabled, .set_next_event will enable it */
+               ctrl &= ~TIMER_CTRL_PERIODIC;
+               writel(ctrl, clkevt_base + TIMER_CTRL);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_RESUME:
+       default:
+               /* Just leave in disabled state */
+               break;
        }
 
-       writel(ctrl, clkevt_base + TIMER_CTRL);
 }
 
 static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
@@ -396,12 +402,10 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device *
 
 static struct clock_event_device integrator_clockevent = {
        .name           = "timer1",
-       .shift          = 34,
-       .features       = CLOCK_EVT_FEAT_PERIODIC,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_mode       = clkevt_set_mode,
        .set_next_event = clkevt_set_next_event,
        .rating         = 300,
-       .cpumask        = cpu_all_mask,
 };
 
 static struct irqaction integrator_timer_irq = {
@@ -411,29 +415,27 @@ static struct irqaction integrator_timer_irq = {
        .dev_id         = &integrator_clockevent,
 };
 
-static void integrator_clockevent_init(u32 khz)
+static void integrator_clockevent_init(unsigned long inrate)
 {
-       struct clock_event_device *evt = &integrator_clockevent;
+       unsigned long rate = inrate;
        unsigned int ctrl = 0;
 
-       if (khz * 1000 > 0x100000 * HZ) {
-               khz /= 256;
+       /* Calculate and program a divisor */
+       if (rate > 0x100000 * HZ) {
+               rate /= 256;
                ctrl |= TIMER_CTRL_DIV256;
-       } else if (khz * 1000 > 0x10000 * HZ) {
-               khz /= 16;
+       } else if (rate > 0x10000 * HZ) {
+               rate /= 16;
                ctrl |= TIMER_CTRL_DIV16;
        }
-
-       timer_reload = khz * 1000 / HZ;
+       timer_reload = rate / HZ;
        writel(ctrl, clkevt_base + TIMER_CTRL);
 
-       evt->irq = IRQ_TIMERINT1;
-       evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);
-       evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);
-       evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
-
        setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
-       clockevents_register_device(evt);
+       clockevents_config_and_register(&integrator_clockevent,
+                                       rate,
+                                       1,
+                                       0xffffU);
 }
 
 /*
@@ -441,14 +443,20 @@ static void integrator_clockevent_init(u32 khz)
  */
 static void __init ap_init_timer(void)
 {
-       u32 khz = TICKS_PER_uSEC * 1000;
+       struct clk *clk;
+       unsigned long rate;
+
+       clk = clk_get_sys("ap_timer", NULL);
+       BUG_ON(IS_ERR(clk));
+       clk_enable(clk);
+       rate = clk_get_rate(clk);
 
        writel(0, TIMER0_VA_BASE + TIMER_CTRL);
        writel(0, TIMER1_VA_BASE + TIMER_CTRL);
        writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 
-       integrator_clocksource_init(khz);
-       integrator_clockevent_init(khz);
+       integrator_clocksource_init(rate);
+       integrator_clockevent_init(rate);
 }
 
 static struct sys_timer ap_timer = {