| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  |  *	pit.c -- Freescale ColdFire PIT timer. Currently this type of | 
					
						
							|  |  |  |  *	         hardware timer only exists in the Freescale ColdFire | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  |  *		 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire | 
					
						
							|  |  |  |  *		 family members will probably use it too. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  |  *	Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  *	Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/param.h>
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							| 
									
										
										
										
											2007-07-27 01:09:00 +10:00
										 |  |  | #include <linux/irq.h>
 | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | #include <linux/clockchips.h>
 | 
					
						
							| 
									
										
										
										
											2007-10-23 14:37:54 +10:00
										 |  |  | #include <asm/machdep.h>
 | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  | #include <asm/io.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <asm/coldfire.h>
 | 
					
						
							|  |  |  | #include <asm/mcfpit.h>
 | 
					
						
							|  |  |  | #include <asm/mcfsim.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *	By default use timer1 as the system clock timer. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | #define	FREQ	((MCF_CLK / 2) / 64)
 | 
					
						
							| 
									
										
										
										
											2011-03-05 23:32:35 +10:00
										 |  |  | #define	TA(a)	(MCFPIT_BASE1 + (a))
 | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | #define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | static u32 pit_cnt; | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Initialize the PIT timer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is also called after resume to bring the PIT into operation again. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void init_cf_pit_timer(enum clock_event_mode mode, | 
					
						
							|  |  |  |                              struct clock_event_device *evt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (mode) { | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_PERIODIC: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 		__raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); | 
					
						
							|  |  |  | 		__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ | 
					
						
							|  |  |  | 				MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \ | 
					
						
							|  |  |  | 				MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_SHUTDOWN: | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_UNUSED: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_ONESHOT: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 		__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ | 
					
						
							|  |  |  | 				MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \ | 
					
						
							|  |  |  | 				TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_RESUME: | 
					
						
							|  |  |  | 		/* Nothing to do here */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Program the next event in oneshot mode | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Delta is given in PIT ticks | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int cf_pit_next_event(unsigned long delta, | 
					
						
							|  |  |  | 		struct clock_event_device *evt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	__raw_writew(delta, TA(MCFPIT_PMR)); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct clock_event_device cf_pit_clockevent = { | 
					
						
							|  |  |  | 	.name		= "pit", | 
					
						
							|  |  |  | 	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 
					
						
							|  |  |  | 	.set_mode	= init_cf_pit_timer, | 
					
						
							|  |  |  | 	.set_next_event	= cf_pit_next_event, | 
					
						
							|  |  |  | 	.shift		= 32, | 
					
						
							| 
									
										
										
										
											2012-06-06 14:02:14 -07:00
										 |  |  | 	.irq		= MCF_IRQ_PIT1, | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | static irqreturn_t pit_tick(int irq, void *dummy) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | 	struct clock_event_device *evt = &cf_pit_clockevent; | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 	u16 pcsr; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Reset the ColdFire timer */ | 
					
						
							| 
									
										
										
										
											2006-06-26 10:33:10 +10:00
										 |  |  | 	pcsr = __raw_readw(TA(MCFPIT_PCSR)); | 
					
						
							|  |  |  | 	__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); | 
					
						
							| 
									
										
										
										
											2007-10-23 14:37:54 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | 	pit_cnt += PIT_CYCLES_PER_JIFFY; | 
					
						
							|  |  |  | 	evt->event_handler(evt); | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | static struct irqaction pit_irq = { | 
					
						
							| 
									
										
										
										
											2007-10-23 14:37:54 +10:00
										 |  |  | 	.name	 = "timer", | 
					
						
							|  |  |  | 	.flags	 = IRQF_DISABLED | IRQF_TIMER, | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 	.handler = pit_tick, | 
					
						
							| 
									
										
										
										
											2007-07-27 01:09:00 +10:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-21 12:24:00 -07:00
										 |  |  | static cycle_t pit_read_clk(struct clocksource *cs) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 cycles; | 
					
						
							|  |  |  | 	u16 pcntr; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 	local_irq_save(flags); | 
					
						
							|  |  |  | 	pcntr = __raw_readw(TA(MCFPIT_PCNTR)); | 
					
						
							|  |  |  | 	cycles = pit_cnt; | 
					
						
							|  |  |  | 	local_irq_restore(flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | 	return cycles + PIT_CYCLES_PER_JIFFY - pcntr; | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | /***************************************************************************/ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | static struct clocksource pit_clk = { | 
					
						
							|  |  |  | 	.name	= "pit", | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | 	.rating	= 100, | 
					
						
							| 
									
										
										
										
											2008-02-01 17:40:21 +10:00
										 |  |  | 	.read	= pit_read_clk, | 
					
						
							|  |  |  | 	.mask	= CLOCKSOURCE_MASK(32), | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /***************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-23 15:34:58 +10:00
										 |  |  | void hw_timer_init(irq_handler_t handler) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-12-13 21:20:26 +10:30
										 |  |  | 	cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); | 
					
						
							| 
									
										
										
										
											2008-04-28 11:43:04 +02:00
										 |  |  | 	cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); | 
					
						
							|  |  |  | 	cf_pit_clockevent.max_delta_ns = | 
					
						
							|  |  |  | 		clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); | 
					
						
							|  |  |  | 	cf_pit_clockevent.min_delta_ns = | 
					
						
							|  |  |  | 		clockevent_delta2ns(0x3f, &cf_pit_clockevent); | 
					
						
							|  |  |  | 	clockevents_register_device(&cf_pit_clockevent); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 14:02:14 -07:00
										 |  |  | 	setup_irq(MCF_IRQ_PIT1, &pit_irq); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-26 20:21:52 -07:00
										 |  |  | 	clocksource_register_hz(&pit_clk, FREQ); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /***************************************************************************/ |