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 int cf_pit_set_periodic(struct clock_event_device *evt) 46{ 47 __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 48 __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); 49 __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | 50 MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | 51 MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); 52 return 0; 53} 54 55static int cf_pit_set_oneshot(struct clock_event_device *evt) 56{ 57 __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 58 __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | 59 MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); 60 return 0; 61} 62 63static int cf_pit_shutdown(struct clock_event_device *evt) 64{ 65 __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 66 return 0; 67} 68 69/* 70 * Program the next event in oneshot mode 71 * 72 * Delta is given in PIT ticks 73 */ 74static int cf_pit_next_event(unsigned long delta, 75 struct clock_event_device *evt) 76{ 77 __raw_writew(delta, TA(MCFPIT_PMR)); 78 return 0; 79} 80 81struct clock_event_device cf_pit_clockevent = { 82 .name = "pit", 83 .features = CLOCK_EVT_FEAT_PERIODIC | 84 CLOCK_EVT_FEAT_ONESHOT, 85 .set_state_shutdown = cf_pit_shutdown, 86 .set_state_periodic = cf_pit_set_periodic, 87 .set_state_oneshot = cf_pit_set_oneshot, 88 .set_next_event = cf_pit_next_event, 89 .shift = 32, 90 .irq = MCF_IRQ_PIT1, 91}; 92 93 94 95/***************************************************************************/ 96 97static irqreturn_t pit_tick(int irq, void *dummy) 98{ 99 struct clock_event_device *evt = &cf_pit_clockevent; 100 u16 pcsr; 101 102 /* Reset the ColdFire timer */ 103 pcsr = __raw_readw(TA(MCFPIT_PCSR)); 104 __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); 105 106 pit_cnt += PIT_CYCLES_PER_JIFFY; 107 evt->event_handler(evt); 108 return IRQ_HANDLED; 109} 110 111/***************************************************************************/ 112 113static struct irqaction pit_irq = { 114 .name = "timer", 115 .flags = IRQF_TIMER, 116 .handler = pit_tick, 117}; 118 119/***************************************************************************/ 120 121static cycle_t pit_read_clk(struct clocksource *cs) 122{ 123 unsigned long flags; 124 u32 cycles; 125 u16 pcntr; 126 127 local_irq_save(flags); 128 pcntr = __raw_readw(TA(MCFPIT_PCNTR)); 129 cycles = pit_cnt; 130 local_irq_restore(flags); 131 132 return cycles + PIT_CYCLES_PER_JIFFY - pcntr; 133} 134 135/***************************************************************************/ 136 137static struct clocksource pit_clk = { 138 .name = "pit", 139 .rating = 100, 140 .read = pit_read_clk, 141 .mask = CLOCKSOURCE_MASK(32), 142}; 143 144/***************************************************************************/ 145 146void hw_timer_init(irq_handler_t handler) 147{ 148 cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); 149 cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); 150 cf_pit_clockevent.max_delta_ns = 151 clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); 152 cf_pit_clockevent.min_delta_ns = 153 clockevent_delta2ns(0x3f, &cf_pit_clockevent); 154 clockevents_register_device(&cf_pit_clockevent); 155 156 setup_irq(MCF_IRQ_PIT1, &pit_irq); 157 158 clocksource_register_hz(&pit_clk, FREQ); 159} 160 161/***************************************************************************/ 162