2006-09-18 23:18:16 +01:00
/*
* arch / arm / plat - iop / time . c
*
* Timer code for IOP32x and IOP33x based systems
*
* Author : Deepak Saxena < dsaxena @ mvista . com >
*
* Copyright 2002 - 2003 MontaVista Software Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/time.h>
# include <linux/init.h>
# include <linux/timex.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2009-10-29 11:46:54 -07:00
# include <linux/clocksource.h>
2009-10-29 11:46:54 -07:00
# include <linux/clockchips.h>
2011-07-31 16:17:29 -04:00
# include <linux/export.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2006-09-18 23:18:16 +01:00
# include <asm/irq.h>
2010-12-15 21:52:10 +00:00
# include <asm/sched_clock.h>
2006-09-18 23:18:16 +01:00
# include <asm/uaccess.h>
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
2008-08-05 16:14:15 +01:00
# include <mach/time.h>
2006-09-18 23:18:16 +01:00
2010-06-02 09:08:55 +01:00
/*
* Minimum clocksource / clockevent timer range in seconds
*/
# define IOP_MIN_RANGE 4
2009-10-29 11:46:54 -07:00
/*
* IOP clocksource ( free - running timer 1 ) .
*/
2010-12-04 06:20:52 +01:00
static cycle_t notrace iop_clocksource_read ( struct clocksource * unused )
2009-10-29 11:46:54 -07:00
{
return 0xffffffffu - read_tcr1 ( ) ;
}
static struct clocksource iop_clocksource = {
. name = " iop_timer1 " ,
. rating = 300 ,
. read = iop_clocksource_read ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2009-10-29 11:46:56 -07:00
/*
* IOP sched_clock ( ) implementation via its clocksource .
*/
2011-12-15 12:19:23 +01:00
static u32 notrace iop_read_sched_clock ( void )
2009-10-29 11:46:56 -07:00
{
2011-12-15 12:19:23 +01:00
return 0xffffffffu - read_tcr1 ( ) ;
2009-10-29 11:46:56 -07:00
}
2009-10-29 11:46:54 -07:00
/*
* IOP clockevents ( interrupting timer 0 ) .
*/
static int iop_set_next_event ( unsigned long delta ,
struct clock_event_device * unused )
{
u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1 ;
BUG_ON ( delta = = 0 ) ;
write_tmr0 ( tmr & ~ ( IOP_TMR_EN | IOP_TMR_RELOAD ) ) ;
write_tcr0 ( delta ) ;
write_tmr0 ( ( tmr & ~ IOP_TMR_RELOAD ) | IOP_TMR_EN ) ;
return 0 ;
}
2006-09-18 23:18:16 +01:00
static unsigned long ticks_per_jiffy ;
2009-10-29 11:46:54 -07:00
static void iop_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * unused )
{
u32 tmr = read_tmr0 ( ) ;
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
write_tmr0 ( tmr & ~ IOP_TMR_EN ) ;
write_tcr0 ( ticks_per_jiffy - 1 ) ;
2010-12-19 15:43:34 +00:00
write_trr0 ( ticks_per_jiffy - 1 ) ;
2009-10-29 11:46:54 -07:00
tmr | = ( IOP_TMR_RELOAD | IOP_TMR_EN ) ;
break ;
case CLOCK_EVT_MODE_ONESHOT :
/* ->set_next_event sets period and enables timer */
tmr & = ~ ( IOP_TMR_RELOAD | IOP_TMR_EN ) ;
break ;
case CLOCK_EVT_MODE_RESUME :
tmr | = IOP_TMR_EN ;
break ;
case CLOCK_EVT_MODE_SHUTDOWN :
case CLOCK_EVT_MODE_UNUSED :
default :
tmr & = ~ IOP_TMR_EN ;
break ;
}
write_tmr0 ( tmr ) ;
}
static struct clock_event_device iop_clockevent = {
. name = " iop_timer0 " ,
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
. rating = 300 ,
. set_next_event = iop_set_next_event ,
. set_mode = iop_set_mode ,
} ;
2006-09-18 23:18:16 +01:00
static irqreturn_t
2007-02-13 17:13:34 +01:00
iop_timer_interrupt ( int irq , void * dev_id )
2006-09-18 23:18:16 +01:00
{
2009-10-29 11:46:54 -07:00
struct clock_event_device * evt = dev_id ;
2006-09-18 23:18:16 +01:00
2009-10-29 11:46:54 -07:00
write_tisr ( 1 ) ;
evt - > event_handler ( evt ) ;
2006-09-18 23:18:16 +01:00
return IRQ_HANDLED ;
}
2007-02-13 17:13:34 +01:00
static struct irqaction iop_timer_irq = {
. name = " IOP Timer Tick " ,
. handler = iop_timer_interrupt ,
2007-05-08 00:35:39 -07:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2009-10-29 11:46:54 -07:00
. dev_id = & iop_clockevent ,
2006-09-18 23:18:16 +01:00
} ;
2007-07-20 02:07:26 +01:00
static unsigned long iop_tick_rate ;
unsigned long get_iop_tick_rate ( void )
{
return iop_tick_rate ;
}
EXPORT_SYMBOL ( get_iop_tick_rate ) ;
2007-02-13 17:13:34 +01:00
void __init iop_init_time ( unsigned long tick_rate )
2006-09-18 23:18:16 +01:00
{
u32 timer_ctl ;
2011-12-15 12:19:23 +01:00
setup_sched_clock ( iop_read_sched_clock , 32 , tick_rate ) ;
2010-12-15 21:52:10 +00:00
2009-08-02 10:46:45 +02:00
ticks_per_jiffy = DIV_ROUND_CLOSEST ( tick_rate , HZ ) ;
2007-07-20 02:07:26 +01:00
iop_tick_rate = tick_rate ;
2006-09-18 23:18:16 +01:00
2007-02-13 17:13:34 +01:00
timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1 ;
2006-09-18 23:18:16 +01:00
/*
2009-10-29 11:46:54 -07:00
* Set up interrupting clockevent timer 0.
2006-09-18 23:18:16 +01:00
*/
2009-10-29 11:46:54 -07:00
write_tmr0 ( timer_ctl & ~ IOP_TMR_EN ) ;
2010-12-19 15:43:34 +00:00
write_tisr ( 1 ) ;
2009-10-29 11:46:54 -07:00
setup_irq ( IRQ_IOP_TIMER0 , & iop_timer_irq ) ;
iop_clockevent . cpumask = cpumask_of ( 0 ) ;
2013-01-12 11:50:05 +00:00
clockevents_config_and_register ( & iop_clockevent , tick_rate ,
0xf , 0xfffffffe ) ;
2009-10-29 11:46:54 -07:00
/*
* Set up free - running clocksource timer 1.
*/
2007-02-13 17:13:34 +01:00
write_trr1 ( 0xffffffff ) ;
2009-10-29 11:46:54 -07:00
write_tcr1 ( 0xffffffff ) ;
2007-02-13 17:13:34 +01:00
write_tmr1 ( timer_ctl ) ;
2010-12-13 13:20:23 +00:00
clocksource_register_hz ( & iop_clocksource , tick_rate ) ;
2006-09-18 23:18:16 +01:00
}