linux/arch/arm/mach-gemini/time.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2001-2006 Storlink, Corp.
   3 *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10#include <linux/interrupt.h>
  11#include <linux/irq.h>
  12#include <linux/io.h>
  13#include <mach/hardware.h>
  14#include <mach/global_reg.h>
  15#include <asm/mach/time.h>
  16#include <linux/clockchips.h>
  17#include <linux/clocksource.h>
  18
  19/*
  20 * Register definitions for the timers
  21 */
  22#define TIMER_COUNT(BASE_ADDR)          (BASE_ADDR  + 0x00)
  23#define TIMER_LOAD(BASE_ADDR)           (BASE_ADDR  + 0x04)
  24#define TIMER_MATCH1(BASE_ADDR)         (BASE_ADDR  + 0x08)
  25#define TIMER_MATCH2(BASE_ADDR)         (BASE_ADDR  + 0x0C)
  26#define TIMER_CR(BASE_ADDR)             (BASE_ADDR  + 0x30)
  27
  28#define TIMER_1_CR_ENABLE               (1 << 0)
  29#define TIMER_1_CR_CLOCK                (1 << 1)
  30#define TIMER_1_CR_INT                  (1 << 2)
  31#define TIMER_2_CR_ENABLE               (1 << 3)
  32#define TIMER_2_CR_CLOCK                (1 << 4)
  33#define TIMER_2_CR_INT                  (1 << 5)
  34#define TIMER_3_CR_ENABLE               (1 << 6)
  35#define TIMER_3_CR_CLOCK                (1 << 7)
  36#define TIMER_3_CR_INT                  (1 << 8)
  37
  38static unsigned int tick_rate;
  39
  40static int gemini_timer_set_next_event(unsigned long cycles,
  41                                       struct clock_event_device *evt)
  42{
  43        u32 cr;
  44
  45        cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  46
  47        /* This may be overdoing it, feel free to test without this */
  48        cr &= ~TIMER_2_CR_ENABLE;
  49        cr &= ~TIMER_2_CR_INT;
  50        writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  51
  52        /* Set next event */
  53        writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
  54        writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
  55        cr |= TIMER_2_CR_ENABLE;
  56        cr |= TIMER_2_CR_INT;
  57        writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  58
  59        return 0;
  60}
  61
  62static void gemini_timer_set_mode(enum clock_event_mode mode,
  63                                  struct clock_event_device *evt)
  64{
  65        u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
  66        u32 cr;
  67
  68        switch (mode) {
  69        case CLOCK_EVT_MODE_PERIODIC:
  70                /* Start the timer */
  71                writel(period,
  72                       TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
  73                writel(period,
  74                       TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
  75                cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  76                cr |= TIMER_2_CR_ENABLE;
  77                cr |= TIMER_2_CR_INT;
  78                writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  79                break;
  80        case CLOCK_EVT_MODE_ONESHOT:
  81        case CLOCK_EVT_MODE_UNUSED:
  82        case CLOCK_EVT_MODE_SHUTDOWN:
  83        case CLOCK_EVT_MODE_RESUME:
  84                /*
  85                 * Disable also for oneshot: the set_next() call will
  86                 * arm the timer instead.
  87                 */
  88                cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  89                cr &= ~TIMER_2_CR_ENABLE;
  90                cr &= ~TIMER_2_CR_INT;
  91                writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
  92                break;
  93        default:
  94                break;
  95        }
  96}
  97
  98/* Use TIMER2 as clock event */
  99static struct clock_event_device gemini_clockevent = {
 100        .name           = "TIMER2",
 101        .rating         = 300, /* Reasonably fast and accurate clock event */
 102        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 103        .set_next_event = gemini_timer_set_next_event,
 104        .set_mode       = gemini_timer_set_mode,
 105};
 106
 107/*
 108 * IRQ handler for the timer
 109 */
 110static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
 111{
 112        struct clock_event_device *evt = &gemini_clockevent;
 113
 114        evt->event_handler(evt);
 115        return IRQ_HANDLED;
 116}
 117
 118static struct irqaction gemini_timer_irq = {
 119        .name           = "Gemini Timer Tick",
 120        .flags          = IRQF_TIMER,
 121        .handler        = gemini_timer_interrupt,
 122};
 123
 124/*
 125 * Set up timer interrupt, and return the current time in seconds.
 126 */
 127void __init gemini_timer_init(void)
 128{
 129        u32 reg_v;
 130
 131        reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
 132        tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000;
 133
 134        printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
 135
 136        tick_rate /= 6;         /* APB bus run AHB*(1/6) */
 137
 138        switch(reg_v & CPU_AHB_RATIO_MASK) {
 139        case CPU_AHB_1_1:
 140                printk(KERN_CONT "(1/1)\n");
 141                break;
 142        case CPU_AHB_3_2:
 143                printk(KERN_CONT "(3/2)\n");
 144                break;
 145        case CPU_AHB_24_13:
 146                printk(KERN_CONT "(24/13)\n");
 147                break;
 148        case CPU_AHB_2_1:
 149                printk(KERN_CONT "(2/1)\n");
 150                break;
 151        }
 152
 153        /*
 154         * Make irqs happen for the system timer
 155         */
 156        setup_irq(IRQ_TIMER2, &gemini_timer_irq);
 157
 158        /* Enable and use TIMER1 as clock source */
 159        writel(0xffffffff, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)));
 160        writel(0xffffffff, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER1_BASE)));
 161        writel(TIMER_1_CR_ENABLE, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
 162        if (clocksource_mmio_init(TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)),
 163                                  "TIMER1", tick_rate, 300, 32,
 164                                  clocksource_mmio_readl_up))
 165                pr_err("timer: failed to initialize gemini clock source\n");
 166
 167        /* Configure and register the clockevent */
 168        clockevents_config_and_register(&gemini_clockevent, tick_rate,
 169                                        1, 0xffffffff);
 170}
 171