linux/arch/arm/plat-spear/time.c
<<
>>
Prefs
   1/*
   2 * arch/arm/plat-spear/time.c
   3 *
   4 * Copyright (C) 2009 ST Microelectronics
   5 * Shiraz Hashim<shiraz.hashim@st.com>
   6 *
   7 * This file is licensed under the terms of the GNU General Public
   8 * License version 2. This program is licensed "as is" without any
   9 * warranty of any kind, whether express or implied.
  10 */
  11
  12#include <linux/clk.h>
  13#include <linux/clockchips.h>
  14#include <linux/clocksource.h>
  15#include <linux/err.h>
  16#include <linux/init.h>
  17#include <linux/interrupt.h>
  18#include <linux/io.h>
  19#include <linux/kernel.h>
  20#include <linux/time.h>
  21#include <linux/irq.h>
  22#include <asm/mach/time.h>
  23#include <mach/irqs.h>
  24#include <mach/hardware.h>
  25#include <mach/spear.h>
  26#include <mach/generic.h>
  27
  28/*
  29 * We would use TIMER0 and TIMER1 as clockevent and clocksource.
  30 * Timer0 and Timer1 both belong to same gpt block in cpu subbsystem. Further
  31 * they share same functional clock. Any change in one's functional clock will
  32 * also affect other timer.
  33 */
  34
  35#define CLKEVT  0       /* gpt0, channel0 as clockevent */
  36#define CLKSRC  1       /* gpt0, channel1 as clocksource */
  37
  38/* Register offsets, x is channel number */
  39#define CR(x)           ((x) * 0x80 + 0x80)
  40#define IR(x)           ((x) * 0x80 + 0x84)
  41#define LOAD(x)         ((x) * 0x80 + 0x88)
  42#define COUNT(x)        ((x) * 0x80 + 0x8C)
  43
  44/* Reg bit definitions */
  45#define CTRL_INT_ENABLE         0x0100
  46#define CTRL_ENABLE             0x0020
  47#define CTRL_ONE_SHOT           0x0010
  48
  49#define CTRL_PRESCALER1         0x0
  50#define CTRL_PRESCALER2         0x1
  51#define CTRL_PRESCALER4         0x2
  52#define CTRL_PRESCALER8         0x3
  53#define CTRL_PRESCALER16        0x4
  54#define CTRL_PRESCALER32        0x5
  55#define CTRL_PRESCALER64        0x6
  56#define CTRL_PRESCALER128       0x7
  57#define CTRL_PRESCALER256       0x8
  58
  59#define INT_STATUS              0x1
  60
  61/*
  62 * Minimum clocksource/clockevent timer range in seconds
  63 */
  64#define SPEAR_MIN_RANGE 4
  65
  66static __iomem void *gpt_base;
  67static struct clk *gpt_clk;
  68
  69static void clockevent_set_mode(enum clock_event_mode mode,
  70                                struct clock_event_device *clk_event_dev);
  71static int clockevent_next_event(unsigned long evt,
  72                                 struct clock_event_device *clk_event_dev);
  73
  74static cycle_t clocksource_read_cycles(struct clocksource *cs)
  75{
  76        return (cycle_t) readw(gpt_base + COUNT(CLKSRC));
  77}
  78
  79static struct clocksource clksrc = {
  80        .name = "tmr1",
  81        .rating = 200,          /* its a pretty decent clock */
  82        .read = clocksource_read_cycles,
  83        .mask = 0xFFFF,         /* 16 bits */
  84        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  85};
  86
  87static void spear_clocksource_init(void)
  88{
  89        u32 tick_rate;
  90        u16 val;
  91
  92        /* program the prescaler (/256)*/
  93        writew(CTRL_PRESCALER256, gpt_base + CR(CLKSRC));
  94
  95        /* find out actual clock driving Timer */
  96        tick_rate = clk_get_rate(gpt_clk);
  97        tick_rate >>= CTRL_PRESCALER256;
  98
  99        writew(0xFFFF, gpt_base + LOAD(CLKSRC));
 100
 101        val = readw(gpt_base + CR(CLKSRC));
 102        val &= ~CTRL_ONE_SHOT;  /* autoreload mode */
 103        val |= CTRL_ENABLE ;
 104        writew(val, gpt_base + CR(CLKSRC));
 105
 106        /* register the clocksource */
 107        clocksource_register_hz(&clksrc, tick_rate);
 108}
 109
 110static struct clock_event_device clkevt = {
 111        .name = "tmr0",
 112        .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 113        .set_mode = clockevent_set_mode,
 114        .set_next_event = clockevent_next_event,
 115        .shift = 0,     /* to be computed */
 116};
 117
 118static void clockevent_set_mode(enum clock_event_mode mode,
 119                                struct clock_event_device *clk_event_dev)
 120{
 121        u32 period;
 122        u16 val;
 123
 124        /* stop the timer */
 125        val = readw(gpt_base + CR(CLKEVT));
 126        val &= ~CTRL_ENABLE;
 127        writew(val, gpt_base + CR(CLKEVT));
 128
 129        switch (mode) {
 130        case CLOCK_EVT_MODE_PERIODIC:
 131                period = clk_get_rate(gpt_clk) / HZ;
 132                period >>= CTRL_PRESCALER16;
 133                writew(period, gpt_base + LOAD(CLKEVT));
 134
 135                val = readw(gpt_base + CR(CLKEVT));
 136                val &= ~CTRL_ONE_SHOT;
 137                val |= CTRL_ENABLE | CTRL_INT_ENABLE;
 138                writew(val, gpt_base + CR(CLKEVT));
 139
 140                break;
 141        case CLOCK_EVT_MODE_ONESHOT:
 142                val = readw(gpt_base + CR(CLKEVT));
 143                val |= CTRL_ONE_SHOT;
 144                writew(val, gpt_base + CR(CLKEVT));
 145
 146                break;
 147        case CLOCK_EVT_MODE_UNUSED:
 148        case CLOCK_EVT_MODE_SHUTDOWN:
 149        case CLOCK_EVT_MODE_RESUME:
 150
 151                break;
 152        default:
 153                pr_err("Invalid mode requested\n");
 154                break;
 155        }
 156}
 157
 158static int clockevent_next_event(unsigned long cycles,
 159                                 struct clock_event_device *clk_event_dev)
 160{
 161        u16 val;
 162
 163        writew(cycles, gpt_base + LOAD(CLKEVT));
 164
 165        val = readw(gpt_base + CR(CLKEVT));
 166        val |= CTRL_ENABLE | CTRL_INT_ENABLE;
 167        writew(val, gpt_base + CR(CLKEVT));
 168
 169        return 0;
 170}
 171
 172static irqreturn_t spear_timer_interrupt(int irq, void *dev_id)
 173{
 174        struct clock_event_device *evt = &clkevt;
 175
 176        writew(INT_STATUS, gpt_base + IR(CLKEVT));
 177
 178        evt->event_handler(evt);
 179
 180        return IRQ_HANDLED;
 181}
 182
 183static struct irqaction spear_timer_irq = {
 184        .name = "timer",
 185        .flags = IRQF_DISABLED | IRQF_TIMER,
 186        .handler = spear_timer_interrupt
 187};
 188
 189static void __init spear_clockevent_init(void)
 190{
 191        u32 tick_rate;
 192
 193        /* program the prescaler */
 194        writew(CTRL_PRESCALER16, gpt_base + CR(CLKEVT));
 195
 196        tick_rate = clk_get_rate(gpt_clk);
 197        tick_rate >>= CTRL_PRESCALER16;
 198
 199        clockevents_calc_mult_shift(&clkevt, tick_rate, SPEAR_MIN_RANGE);
 200
 201        clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
 202                        &clkevt);
 203        clkevt.min_delta_ns = clockevent_delta2ns(3, &clkevt);
 204
 205        clkevt.cpumask = cpumask_of(0);
 206
 207        clockevents_register_device(&clkevt);
 208
 209        setup_irq(SPEAR_GPT0_CHAN0_IRQ, &spear_timer_irq);
 210}
 211
 212void __init spear_setup_timer(void)
 213{
 214        struct clk *pll3_clk;
 215
 216        if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) {
 217                pr_err("%s:cannot get IO addr\n", __func__);
 218                return;
 219        }
 220
 221        gpt_base = (void __iomem *)ioremap(SPEAR_GPT0_BASE, SZ_1K);
 222        if (!gpt_base) {
 223                pr_err("%s:ioremap failed for gpt\n", __func__);
 224                goto err_mem;
 225        }
 226
 227        gpt_clk = clk_get_sys("gpt0", NULL);
 228        if (!gpt_clk) {
 229                pr_err("%s:couldn't get clk for gpt\n", __func__);
 230                goto err_iomap;
 231        }
 232
 233        pll3_clk = clk_get(NULL, "pll3_48m_clk");
 234        if (!pll3_clk) {
 235                pr_err("%s:couldn't get PLL3 as parent for gpt\n", __func__);
 236                goto err_iomap;
 237        }
 238
 239        clk_set_parent(gpt_clk, pll3_clk);
 240
 241        spear_clockevent_init();
 242        spear_clocksource_init();
 243
 244        return;
 245
 246err_iomap:
 247        iounmap(gpt_base);
 248
 249err_mem:
 250        release_mem_region(SPEAR_GPT0_BASE, SZ_1K);
 251}
 252
 253struct sys_timer spear_sys_timer = {
 254        .init = spear_setup_timer,
 255};
 256