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