2006-01-09 20:05:41 +03:00
/*
2007-02-05 13:42:07 +03:00
* linux / arch / arm / mach - at91 / at91rm9200_time . c
2006-01-09 20:05:41 +03:00
*
* Copyright ( C ) 2003 SAN People
* Copyright ( C ) 2003 ATMEL
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2007-07-31 04:41:26 +04:00
# include <linux/kernel.h>
2006-01-09 20:05:41 +03:00
# include <linux/interrupt.h>
2006-07-02 02:01:50 +04:00
# include <linux/irq.h>
2007-07-31 04:41:26 +04:00
# include <linux/clockchips.h>
2006-01-09 20:05:41 +03:00
# include <asm/mach/time.h>
2008-08-05 19:14:15 +04:00
# include <mach/at91_st.h>
2006-11-30 19:16:43 +03:00
2006-06-19 18:23:41 +04:00
static unsigned long last_crtr ;
2007-07-31 04:41:26 +04:00
static u32 irqmask ;
static struct clock_event_device clkevt ;
2006-06-19 18:23:41 +04:00
2006-01-09 20:05:41 +03:00
/*
2007-07-31 04:41:26 +04:00
* The ST_CRTR is updated asynchronously to the master clock . . . but
* the updates as seen by the CPU don ' t seem to be strictly monotonic .
* Waiting until we read the same value twice avoids glitching .
2006-01-09 20:05:41 +03:00
*/
2007-07-31 04:41:26 +04:00
static inline unsigned long read_CRTR ( void )
{
2006-01-09 20:05:41 +03:00
unsigned long x1 , x2 ;
2007-07-31 04:41:26 +04:00
x1 = at91_sys_read ( AT91_ST_CRTR ) ;
2006-01-09 20:05:41 +03:00
do {
x2 = at91_sys_read ( AT91_ST_CRTR ) ;
2007-07-31 04:41:26 +04:00
if ( x1 = = x2 )
break ;
x1 = x2 ;
} while ( 1 ) ;
2006-01-09 20:05:41 +03:00
return x1 ;
}
/*
* IRQ handler for the timer .
*/
2006-10-06 21:53:39 +04:00
static irqreturn_t at91rm9200_timer_interrupt ( int irq , void * dev_id )
2006-01-09 20:05:41 +03:00
{
2007-07-31 04:41:26 +04:00
u32 sr = at91_sys_read ( AT91_ST_SR ) & irqmask ;
2006-01-09 20:05:41 +03:00
2007-07-31 04:41:26 +04:00
/* simulate "oneshot" timer with alarm */
if ( sr & AT91_ST_ALMS ) {
clkevt . event_handler ( & clkevt ) ;
return IRQ_HANDLED ;
}
2006-01-09 20:05:41 +03:00
2007-07-31 04:41:26 +04:00
/* periodic mode should handle delayed ticks */
if ( sr & AT91_ST_PITS ) {
u32 crtr = read_CRTR ( ) ;
2006-01-09 20:05:41 +03:00
2007-07-31 04:41:26 +04:00
while ( ( ( crtr - last_crtr ) & AT91_ST_CRTV ) > = LATCH ) {
last_crtr + = LATCH ;
clkevt . event_handler ( & clkevt ) ;
}
2006-01-09 20:05:41 +03:00
return IRQ_HANDLED ;
}
2007-07-31 04:41:26 +04:00
/* this irq is shared ... */
return IRQ_NONE ;
2006-01-09 20:05:41 +03:00
}
static struct irqaction at91rm9200_timer_irq = {
. name = " at91_tick " ,
2007-05-08 11:35:39 +04:00
. flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2006-01-09 20:05:41 +03:00
. handler = at91rm9200_timer_interrupt
} ;
2007-07-31 04:41:26 +04:00
static cycle_t read_clk32k ( void )
2006-06-19 18:26:50 +04:00
{
2007-07-31 04:41:26 +04:00
return read_CRTR ( ) ;
}
2006-06-19 18:26:50 +04:00
2007-07-31 04:41:26 +04:00
static struct clocksource clk32k = {
. name = " 32k_counter " ,
. rating = 150 ,
. read = read_clk32k ,
. mask = CLOCKSOURCE_MASK ( 20 ) ,
. shift = 10 ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
static void
clkevt32k_mode ( enum clock_event_mode mode , struct clock_event_device * dev )
{
/* Disable and flush pending timer interrupts */
at91_sys_write ( AT91_ST_IDR , AT91_ST_PITS | AT91_ST_ALMS ) ;
( void ) at91_sys_read ( AT91_ST_SR ) ;
2006-06-19 18:26:50 +04:00
2007-07-31 04:41:26 +04:00
last_crtr = read_CRTR ( ) ;
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
/* PIT for periodic irqs; fixed rate of 1/HZ */
irqmask = AT91_ST_PITS ;
at91_sys_write ( AT91_ST_PIMR , LATCH ) ;
break ;
case CLOCK_EVT_MODE_ONESHOT :
/* ALM for oneshot irqs, set by next_event()
* before 32 seconds have passed
*/
irqmask = AT91_ST_ALMS ;
at91_sys_write ( AT91_ST_RTAR , last_crtr ) ;
break ;
case CLOCK_EVT_MODE_SHUTDOWN :
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_RESUME :
irqmask = 0 ;
break ;
}
at91_sys_write ( AT91_ST_IER , irqmask ) ;
}
2006-06-19 18:26:50 +04:00
2007-07-31 04:41:26 +04:00
static int
clkevt32k_next_event ( unsigned long delta , struct clock_event_device * dev )
{
unsigned long flags ;
u32 alm ;
int status = 0 ;
BUG_ON ( delta < 2 ) ;
/* Use "raw" primitives so we behave correctly on RT kernels. */
raw_local_irq_save ( flags ) ;
/* The alarm IRQ uses absolute time (now+delta), not the relative
* time ( delta ) in our calling convention . Like all clockevents
* using such " match " hardware , we have a race to defend against .
*
* Our defense here is to have set up the clockevent device so the
* delta is at least two . That way we never end up writing RTAR
* with the value then held in CRTR . . . which would mean the match
* wouldn ' t trigger until 32 seconds later , after CRTR wraps .
*/
alm = read_CRTR ( ) ;
/* Cancel any pending alarm; flush any pending IRQ */
at91_sys_write ( AT91_ST_RTAR , alm ) ;
2006-12-01 12:15:04 +03:00
( void ) at91_sys_read ( AT91_ST_SR ) ;
2007-07-31 04:41:26 +04:00
/* Schedule alarm by writing RTAR. */
alm + = delta ;
at91_sys_write ( AT91_ST_RTAR , alm ) ;
raw_local_irq_restore ( flags ) ;
return status ;
2006-06-19 18:26:50 +04:00
}
2007-07-31 04:41:26 +04:00
static struct clock_event_device clkevt = {
. name = " at91_tick " ,
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
. shift = 32 ,
. rating = 150 ,
. cpumask = CPU_MASK_CPU0 ,
. set_next_event = clkevt32k_next_event ,
. set_mode = clkevt32k_mode ,
} ;
2006-01-09 20:05:41 +03:00
/*
2007-07-31 04:41:26 +04:00
* ST ( system timer ) module supports both clockevents and clocksource .
2006-01-09 20:05:41 +03:00
*/
void __init at91rm9200_timer_init ( void )
{
2007-07-31 04:41:26 +04:00
/* Disable all timer interrupts, and clear any pending ones */
at91_sys_write ( AT91_ST_IDR ,
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS ) ;
( void ) at91_sys_read ( AT91_ST_SR ) ;
2006-01-09 20:05:41 +03:00
2006-06-19 18:26:50 +04:00
/* Make IRQs happen for the system timer */
2006-01-09 20:05:41 +03:00
setup_irq ( AT91_ID_SYS , & at91rm9200_timer_irq ) ;
2007-07-31 04:41:26 +04:00
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
* directly for the clocksource and all clockevents , after adjusting
* its prescaler from the 1 Hz default .
*/
at91_sys_write ( AT91_ST_RTMR , 1 ) ;
2006-01-09 20:05:41 +03:00
2007-07-31 04:41:26 +04:00
/* Setup timer clockevent, with minimum of two ticks (important!!) */
clkevt . mult = div_sc ( AT91_SLOW_CLOCK , NSEC_PER_SEC , clkevt . shift ) ;
clkevt . max_delta_ns = clockevent_delta2ns ( AT91_ST_ALMV , & clkevt ) ;
clkevt . min_delta_ns = clockevent_delta2ns ( 2 , & clkevt ) + 1 ;
clkevt . cpumask = cpumask_of_cpu ( 0 ) ;
clockevents_register_device ( & clkevt ) ;
2006-06-19 18:26:50 +04:00
2007-07-31 04:41:26 +04:00
/* register clocksource */
clk32k . mult = clocksource_hz2mult ( AT91_SLOW_CLOCK , clk32k . shift ) ;
clocksource_register ( & clk32k ) ;
2006-01-09 20:05:41 +03:00
}
struct sys_timer at91rm9200_timer = {
. init = at91rm9200_timer_init ,
} ;
2006-06-19 18:26:50 +04:00