linux/arch/arm/mach-w90x900/time.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-w90x900/time.c
   3 *
   4 * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks
   5 *
   6 * Copyright (c) 2009 Nuvoton technology corporation
   7 * All rights reserved.
   8 *
   9 * Wan ZongShun <mcuos.com@gmail.com>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/sched.h>
  20#include <linux/init.h>
  21#include <linux/interrupt.h>
  22#include <linux/err.h>
  23#include <linux/clk.h>
  24#include <linux/io.h>
  25#include <linux/leds.h>
  26#include <linux/clocksource.h>
  27#include <linux/clockchips.h>
  28
  29#include <asm/mach-types.h>
  30#include <asm/mach/irq.h>
  31#include <asm/mach/time.h>
  32
  33#include <mach/map.h>
  34#include <mach/regs-timer.h>
  35
  36#include "nuc9xx.h"
  37
  38#define RESETINT        0x1f
  39#define PERIOD          (0x01 << 27)
  40#define ONESHOT         (0x00 << 27)
  41#define COUNTEN         (0x01 << 30)
  42#define INTEN           (0x01 << 29)
  43
  44#define TICKS_PER_SEC   100
  45#define PRESCALE        0x63 /* Divider = prescale + 1 */
  46
  47#define TDR_SHIFT       24
  48
  49static unsigned int timer0_load;
  50
  51static void nuc900_clockevent_setmode(enum clock_event_mode mode,
  52                struct clock_event_device *clk)
  53{
  54        unsigned int val;
  55
  56        val = __raw_readl(REG_TCSR0);
  57        val &= ~(0x03 << 27);
  58
  59        switch (mode) {
  60        case CLOCK_EVT_MODE_PERIODIC:
  61                __raw_writel(timer0_load, REG_TICR0);
  62                val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
  63                break;
  64
  65        case CLOCK_EVT_MODE_ONESHOT:
  66                val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
  67                break;
  68
  69        case CLOCK_EVT_MODE_UNUSED:
  70        case CLOCK_EVT_MODE_SHUTDOWN:
  71        case CLOCK_EVT_MODE_RESUME:
  72                break;
  73        }
  74
  75        __raw_writel(val, REG_TCSR0);
  76}
  77
  78static int nuc900_clockevent_setnextevent(unsigned long evt,
  79                struct clock_event_device *clk)
  80{
  81        unsigned int val;
  82
  83        __raw_writel(evt, REG_TICR0);
  84
  85        val = __raw_readl(REG_TCSR0);
  86        val |= (COUNTEN | INTEN | PRESCALE);
  87        __raw_writel(val, REG_TCSR0);
  88
  89        return 0;
  90}
  91
  92static struct clock_event_device nuc900_clockevent_device = {
  93        .name           = "nuc900-timer0",
  94        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  95        .set_mode       = nuc900_clockevent_setmode,
  96        .set_next_event = nuc900_clockevent_setnextevent,
  97        .rating         = 300,
  98};
  99
 100/*IRQ handler for the timer*/
 101
 102static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id)
 103{
 104        struct clock_event_device *evt = &nuc900_clockevent_device;
 105
 106        __raw_writel(0x01, REG_TISR); /* clear TIF0 */
 107
 108        evt->event_handler(evt);
 109        return IRQ_HANDLED;
 110}
 111
 112static struct irqaction nuc900_timer0_irq = {
 113        .name           = "nuc900-timer0",
 114        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 115        .handler        = nuc900_timer0_interrupt,
 116};
 117
 118static void __init nuc900_clockevents_init(void)
 119{
 120        unsigned int rate;
 121        struct clk *clk = clk_get(NULL, "timer0");
 122
 123        BUG_ON(IS_ERR(clk));
 124
 125        __raw_writel(0x00, REG_TCSR0);
 126
 127        clk_enable(clk);
 128        rate = clk_get_rate(clk) / (PRESCALE + 1);
 129
 130        timer0_load = (rate / TICKS_PER_SEC);
 131
 132        __raw_writel(RESETINT, REG_TISR);
 133        setup_irq(IRQ_TIMER0, &nuc900_timer0_irq);
 134
 135        nuc900_clockevent_device.cpumask = cpumask_of(0);
 136
 137        clockevents_config_and_register(&nuc900_clockevent_device, rate,
 138                                        0xf, 0xffffffff);
 139}
 140
 141static void __init nuc900_clocksource_init(void)
 142{
 143        unsigned int val;
 144        unsigned int rate;
 145        struct clk *clk = clk_get(NULL, "timer1");
 146
 147        BUG_ON(IS_ERR(clk));
 148
 149        __raw_writel(0x00, REG_TCSR1);
 150
 151        clk_enable(clk);
 152        rate = clk_get_rate(clk) / (PRESCALE + 1);
 153
 154        __raw_writel(0xffffffff, REG_TICR1);
 155
 156        val = __raw_readl(REG_TCSR1);
 157        val |= (COUNTEN | PERIOD | PRESCALE);
 158        __raw_writel(val, REG_TCSR1);
 159
 160        clocksource_mmio_init(REG_TDR1, "nuc900-timer1", rate, 200,
 161                TDR_SHIFT, clocksource_mmio_readl_down);
 162}
 163
 164void __init nuc900_timer_init(void)
 165{
 166        nuc900_clocksource_init();
 167        nuc900_clockevents_init();
 168}
 169