linux/arch/m68k/platform/coldfire/pit.c
<<
>>
Prefs
   1/***************************************************************************/
   2
   3/*
   4 *      pit.c -- Freescale ColdFire PIT timer. Currently this type of
   5 *               hardware timer only exists in the Freescale ColdFire
   6 *               5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
   7 *               family members will probably use it too.
   8 *
   9 *      Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
  10 *      Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
  11 */
  12
  13/***************************************************************************/
  14
  15#include <linux/kernel.h>
  16#include <linux/sched.h>
  17#include <linux/param.h>
  18#include <linux/init.h>
  19#include <linux/interrupt.h>
  20#include <linux/irq.h>
  21#include <linux/clockchips.h>
  22#include <asm/machdep.h>
  23#include <asm/io.h>
  24#include <asm/coldfire.h>
  25#include <asm/mcfpit.h>
  26#include <asm/mcfsim.h>
  27
  28/***************************************************************************/
  29
  30/*
  31 *      By default use timer1 as the system clock timer.
  32 */
  33#define FREQ    ((MCF_CLK / 2) / 64)
  34#define TA(a)   (MCFPIT_BASE1 + (a))
  35#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
  36
  37static u32 pit_cnt;
  38
  39/*
  40 * Initialize the PIT timer.
  41 *
  42 * This is also called after resume to bring the PIT into operation again.
  43 */
  44
  45static void init_cf_pit_timer(enum clock_event_mode mode,
  46                             struct clock_event_device *evt)
  47{
  48        switch (mode) {
  49        case CLOCK_EVT_MODE_PERIODIC:
  50
  51                __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  52                __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
  53                __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
  54                                MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
  55                                MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
  56                break;
  57
  58        case CLOCK_EVT_MODE_SHUTDOWN:
  59        case CLOCK_EVT_MODE_UNUSED:
  60
  61                __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  62                break;
  63
  64        case CLOCK_EVT_MODE_ONESHOT:
  65
  66                __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  67                __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
  68                                MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
  69                                TA(MCFPIT_PCSR));
  70                break;
  71
  72        case CLOCK_EVT_MODE_RESUME:
  73                /* Nothing to do here */
  74                break;
  75        }
  76}
  77
  78/*
  79 * Program the next event in oneshot mode
  80 *
  81 * Delta is given in PIT ticks
  82 */
  83static int cf_pit_next_event(unsigned long delta,
  84                struct clock_event_device *evt)
  85{
  86        __raw_writew(delta, TA(MCFPIT_PMR));
  87        return 0;
  88}
  89
  90struct clock_event_device cf_pit_clockevent = {
  91        .name           = "pit",
  92        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  93        .set_mode       = init_cf_pit_timer,
  94        .set_next_event = cf_pit_next_event,
  95        .shift          = 32,
  96        .irq            = MCF_IRQ_PIT1,
  97};
  98
  99
 100
 101/***************************************************************************/
 102
 103static irqreturn_t pit_tick(int irq, void *dummy)
 104{
 105        struct clock_event_device *evt = &cf_pit_clockevent;
 106        u16 pcsr;
 107
 108        /* Reset the ColdFire timer */
 109        pcsr = __raw_readw(TA(MCFPIT_PCSR));
 110        __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
 111
 112        pit_cnt += PIT_CYCLES_PER_JIFFY;
 113        evt->event_handler(evt);
 114        return IRQ_HANDLED;
 115}
 116
 117/***************************************************************************/
 118
 119static struct irqaction pit_irq = {
 120        .name    = "timer",
 121        .flags   = IRQF_DISABLED | IRQF_TIMER,
 122        .handler = pit_tick,
 123};
 124
 125/***************************************************************************/
 126
 127static cycle_t pit_read_clk(struct clocksource *cs)
 128{
 129        unsigned long flags;
 130        u32 cycles;
 131        u16 pcntr;
 132
 133        local_irq_save(flags);
 134        pcntr = __raw_readw(TA(MCFPIT_PCNTR));
 135        cycles = pit_cnt;
 136        local_irq_restore(flags);
 137
 138        return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
 139}
 140
 141/***************************************************************************/
 142
 143static struct clocksource pit_clk = {
 144        .name   = "pit",
 145        .rating = 100,
 146        .read   = pit_read_clk,
 147        .mask   = CLOCKSOURCE_MASK(32),
 148};
 149
 150/***************************************************************************/
 151
 152void hw_timer_init(irq_handler_t handler)
 153{
 154        cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
 155        cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
 156        cf_pit_clockevent.max_delta_ns =
 157                clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
 158        cf_pit_clockevent.min_delta_ns =
 159                clockevent_delta2ns(0x3f, &cf_pit_clockevent);
 160        clockevents_register_device(&cf_pit_clockevent);
 161
 162        setup_irq(MCF_IRQ_PIT1, &pit_irq);
 163
 164        clocksource_register_hz(&pit_clk, FREQ);
 165}
 166
 167/***************************************************************************/
 168