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 38 static 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 46 static 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 56 static 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 64 static 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 */ 75 static 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 82 struct 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 98 static 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 114 static 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 130 static struct clocksource pit_clk = { 131 .name = "pit", 132 .rating = 100, 133 .read = pit_read_clk, 134 .mask = CLOCKSOURCE_MASK(32), 135 }; 136 137 /***************************************************************************/ 138 139 void 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 /***************************************************************************/ 163
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.