Path: blob/master/arch/m68k/platform/coldfire/pit.c
10819 views
/***************************************************************************/12/*3* pit.c -- Freescale ColdFire PIT timer. Currently this type of4* hardware timer only exists in the Freescale ColdFire5* 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire6* family members will probably use it too.7*8* Copyright (C) 1999-2008, Greg Ungerer ([email protected])9* Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)10*/1112/***************************************************************************/1314#include <linux/kernel.h>15#include <linux/sched.h>16#include <linux/param.h>17#include <linux/init.h>18#include <linux/interrupt.h>19#include <linux/irq.h>20#include <linux/clockchips.h>21#include <asm/machdep.h>22#include <asm/io.h>23#include <asm/coldfire.h>24#include <asm/mcfpit.h>25#include <asm/mcfsim.h>2627/***************************************************************************/2829/*30* By default use timer1 as the system clock timer.31*/32#define FREQ ((MCF_CLK / 2) / 64)33#define TA(a) (MCFPIT_BASE1 + (a))34#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)3536static u32 pit_cnt;3738/*39* Initialize the PIT timer.40*41* This is also called after resume to bring the PIT into operation again.42*/4344static void init_cf_pit_timer(enum clock_event_mode mode,45struct clock_event_device *evt)46{47switch (mode) {48case CLOCK_EVT_MODE_PERIODIC:4950__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));51__raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));52__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \53MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \54MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));55break;5657case CLOCK_EVT_MODE_SHUTDOWN:58case CLOCK_EVT_MODE_UNUSED:5960__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));61break;6263case CLOCK_EVT_MODE_ONESHOT:6465__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));66__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \67MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \68TA(MCFPIT_PCSR));69break;7071case CLOCK_EVT_MODE_RESUME:72/* Nothing to do here */73break;74}75}7677/*78* Program the next event in oneshot mode79*80* Delta is given in PIT ticks81*/82static int cf_pit_next_event(unsigned long delta,83struct clock_event_device *evt)84{85__raw_writew(delta, TA(MCFPIT_PMR));86return 0;87}8889struct clock_event_device cf_pit_clockevent = {90.name = "pit",91.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,92.set_mode = init_cf_pit_timer,93.set_next_event = cf_pit_next_event,94.shift = 32,95.irq = MCFINT_VECBASE + MCFINT_PIT1,96};979899100/***************************************************************************/101102static irqreturn_t pit_tick(int irq, void *dummy)103{104struct clock_event_device *evt = &cf_pit_clockevent;105u16 pcsr;106107/* Reset the ColdFire timer */108pcsr = __raw_readw(TA(MCFPIT_PCSR));109__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));110111pit_cnt += PIT_CYCLES_PER_JIFFY;112evt->event_handler(evt);113return IRQ_HANDLED;114}115116/***************************************************************************/117118static struct irqaction pit_irq = {119.name = "timer",120.flags = IRQF_DISABLED | IRQF_TIMER,121.handler = pit_tick,122};123124/***************************************************************************/125126static cycle_t pit_read_clk(struct clocksource *cs)127{128unsigned long flags;129u32 cycles;130u16 pcntr;131132local_irq_save(flags);133pcntr = __raw_readw(TA(MCFPIT_PCNTR));134cycles = pit_cnt;135local_irq_restore(flags);136137return cycles + PIT_CYCLES_PER_JIFFY - pcntr;138}139140/***************************************************************************/141142static struct clocksource pit_clk = {143.name = "pit",144.rating = 100,145.read = pit_read_clk,146.shift = 20,147.mask = CLOCKSOURCE_MASK(32),148};149150/***************************************************************************/151152void hw_timer_init(void)153{154cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());155cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);156cf_pit_clockevent.max_delta_ns =157clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);158cf_pit_clockevent.min_delta_ns =159clockevent_delta2ns(0x3f, &cf_pit_clockevent);160clockevents_register_device(&cf_pit_clockevent);161162setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);163164pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);165clocksource_register(&pit_clk);166}167168/***************************************************************************/169170171