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 " ,
2013-09-07 07:43:08 +02:00
. flags = 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
}
/***************************************************************************/