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>
2012-04-04 21:15:15 +04:00
# include <linux/export.h>
2012-10-28 22:31:07 +04:00
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.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>
2013-11-14 13:49:19 +04:00
# include <mach/hardware.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
2011-10-16 14:17:09 +04:00
# define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ / 2) / HZ)
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 ;
2012-02-20 14:07:39 +04:00
x1 = at91_st_read ( AT91_ST_CRTR ) ;
2006-01-09 20:05:41 +03:00
do {
2012-02-20 14:07:39 +04:00
x2 = at91_st_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
{
2012-02-20 14:07:39 +04:00
u32 sr = at91_st_read ( AT91_ST_SR ) & irqmask ;
2006-01-09 20:05:41 +03:00
2009-09-21 11:30:09 +04:00
/*
* irqs should be disabled here , but as the irq is shared they are only
* guaranteed to be off if the timer irq is registered first .
*/
WARN_ON_ONCE ( ! irqs_disabled ( ) ) ;
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
2011-10-16 14:17:09 +04:00
while ( ( ( crtr - last_crtr ) & AT91_ST_CRTV ) > = RM9200_TIMER_LATCH ) {
last_crtr + = RM9200_TIMER_LATCH ;
2007-07-31 04:41:26 +04:00
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 " ,
2013-09-04 08:54:39 +04:00
. flags = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL ,
2012-10-28 22:31:07 +04:00
. handler = at91rm9200_timer_interrupt ,
. irq = NR_IRQS_LEGACY + AT91_ID_SYS ,
2006-01-09 20:05:41 +03:00
} ;
2009-04-21 23:24:00 +04:00
static cycle_t read_clk32k ( struct clocksource * cs )
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 ) ,
. 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 */
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_IDR , AT91_ST_PITS | AT91_ST_ALMS ) ;
2012-02-20 14:13:13 +04:00
at91_st_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 ;
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_PIMR , RM9200_TIMER_LATCH ) ;
2007-07-31 04:41:26 +04:00
break ;
case CLOCK_EVT_MODE_ONESHOT :
/* ALM for oneshot irqs, set by next_event()
* before 32 seconds have passed
*/
irqmask = AT91_ST_ALMS ;
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_RTAR , last_crtr ) ;
2007-07-31 04:41:26 +04:00
break ;
case CLOCK_EVT_MODE_SHUTDOWN :
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_RESUME :
irqmask = 0 ;
break ;
}
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_IER , irqmask ) ;
2007-07-31 04:41:26 +04:00
}
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 )
{
u32 alm ;
int status = 0 ;
BUG_ON ( delta < 2 ) ;
/* 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 */
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_RTAR , alm ) ;
2012-02-20 14:13:13 +04:00
at91_st_read ( AT91_ST_SR ) ;
2006-12-01 12:15:04 +03:00
2007-07-31 04:41:26 +04:00
/* Schedule alarm by writing RTAR. */
alm + = delta ;
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_RTAR , alm ) ;
2007-07-31 04:41:26 +04:00
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 ,
. rating = 150 ,
. set_next_event = clkevt32k_next_event ,
. set_mode = clkevt32k_mode ,
} ;
2012-02-20 14:07:39 +04:00
void __iomem * at91_st_base ;
2012-04-04 21:15:15 +04:00
EXPORT_SYMBOL_GPL ( at91_st_base ) ;
2012-02-20 14:07:39 +04:00
2012-10-28 22:31:07 +04:00
# ifdef CONFIG_OF
static struct of_device_id at91rm9200_st_timer_ids [ ] = {
{ . compatible = " atmel,at91rm9200-st " } ,
{ /* sentinel */ }
} ;
static int __init of_at91rm9200_st_init ( void )
{
struct device_node * np ;
int ret ;
np = of_find_matching_node ( NULL , at91rm9200_st_timer_ids ) ;
if ( ! np )
goto err ;
at91_st_base = of_iomap ( np , 0 ) ;
if ( ! at91_st_base )
goto node_err ;
/* Get the interrupts property */
ret = irq_of_parse_and_map ( np , 0 ) ;
if ( ! ret )
goto ioremap_err ;
at91rm9200_timer_irq . irq = ret ;
of_node_put ( np ) ;
return 0 ;
ioremap_err :
iounmap ( at91_st_base ) ;
node_err :
of_node_put ( np ) ;
err :
return - EINVAL ;
}
# else
static int __init of_at91rm9200_st_init ( void )
{
return - EINVAL ;
}
# endif
2012-02-20 14:07:39 +04:00
void __init at91rm9200_ioremap_st ( u32 addr )
{
2012-10-28 22:31:07 +04:00
# ifdef CONFIG_OF
struct device_node * np ;
np = of_find_matching_node ( NULL , at91rm9200_st_timer_ids ) ;
if ( np ) {
of_node_put ( np ) ;
return ;
}
# endif
2012-02-20 14:07:39 +04:00
at91_st_base = ioremap ( addr , 256 ) ;
if ( ! at91_st_base )
panic ( " Impossible to ioremap ST \n " ) ;
}
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 )
{
2012-10-28 22:31:07 +04:00
/* For device tree enabled device: initialize here */
of_at91rm9200_st_init ( ) ;
2007-07-31 04:41:26 +04:00
/* Disable all timer interrupts, and clear any pending ones */
2012-02-20 14:07:39 +04:00
at91_st_write ( AT91_ST_IDR ,
2007-07-31 04:41:26 +04:00
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS ) ;
2012-02-20 14:13:13 +04:00
at91_st_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 */
2012-10-28 22:31:07 +04:00
setup_irq ( at91rm9200_timer_irq . irq , & at91rm9200_timer_irq ) ;
2006-01-09 20:05:41 +03:00
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 .
*/
2012-02-20 14:07:39 +04:00
at91_st_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!!) */
2008-12-13 13:50:26 +03:00
clkevt . cpumask = cpumask_of ( 0 ) ;
2013-10-08 18:38:53 +04:00
clockevents_config_and_register ( & clkevt , AT91_SLOW_CLOCK ,
2 , AT91_ST_ALMV ) ;
2006-06-19 18:26:50 +04:00
2007-07-31 04:41:26 +04:00
/* register clocksource */
2010-12-13 16:14:55 +03:00
clocksource_register_hz ( & clk32k , AT91_SLOW_CLOCK ) ;
2006-01-09 20:05:41 +03:00
}