2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / common / time - acorn . c
*
* Copyright ( c ) 1996 - 2000 Russell King .
*
* Changelog :
* 24 - Sep - 1996 RMK Created
* 10 - Oct - 1996 RMK Brought up to date with arch - sa110eval
* 04 - Dec - 1997 RMK Updated for new arch / arm / time . c
* 13 = Jun - 2004 DS Moved to arch / arm / common b / c shared w / CLPS7500
*/
2018-11-14 19:13:02 +00:00
# include <linux/clocksource.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/interrupt.h>
2006-07-01 22:32:14 +01:00
# include <linux/irq.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-04-16 15:20:36 -07:00
# include <asm/hardware/ioc.h>
# include <asm/mach/time.h>
2013-12-19 22:22:23 +01:00
# define RPC_CLOCK_FREQ 2000000
# define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
2018-11-14 19:13:02 +00:00
static u32 ioc_time ;
static u64 ioc_timer_read ( struct clocksource * cs )
2005-04-16 15:20:36 -07:00
{
unsigned int count1 , count2 , status ;
2018-11-14 19:13:02 +00:00
unsigned long flags ;
u32 ticks ;
2005-04-16 15:20:36 -07:00
2018-11-14 19:13:02 +00:00
local_irq_save ( flags ) ;
2005-04-16 15:20:36 -07:00
ioc_writeb ( 0 , IOC_T0LATCH ) ;
barrier ( ) ;
count1 = ioc_readb ( IOC_T0CNTL ) | ( ioc_readb ( IOC_T0CNTH ) < < 8 ) ;
barrier ( ) ;
status = ioc_readb ( IOC_IRQREQA ) ;
barrier ( ) ;
ioc_writeb ( 0 , IOC_T0LATCH ) ;
barrier ( ) ;
count2 = ioc_readb ( IOC_T0CNTL ) | ( ioc_readb ( IOC_T0CNTH ) < < 8 ) ;
2018-11-14 19:13:02 +00:00
ticks = ioc_time + RPC_LATCH - count2 ;
local_irq_restore ( flags ) ;
2005-04-16 15:20:36 -07:00
if ( count2 < count1 ) {
/*
2018-11-14 19:13:02 +00:00
* The timer has not reloaded between reading count1 and
* count2 , check whether an interrupt was actually pending .
2005-04-16 15:20:36 -07:00
*/
if ( status & ( 1 < < 5 ) )
2018-11-14 19:13:02 +00:00
ticks + = RPC_LATCH ;
2005-04-16 15:20:36 -07:00
} else if ( count2 > count1 ) {
/*
2018-11-14 19:13:02 +00:00
* The timer has reloaded , so count2 indicates the new
* count since the wrap . The interrupt would not have
* been processed , so add the missed ticks .
2005-04-16 15:20:36 -07:00
*/
2018-11-14 19:13:02 +00:00
ticks + = RPC_LATCH ;
2005-04-16 15:20:36 -07:00
}
2018-11-14 19:13:02 +00:00
return ticks ;
2005-04-16 15:20:36 -07:00
}
2018-11-14 19:13:02 +00:00
static struct clocksource ioctime_clocksource = {
. read = ioc_timer_read ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. rating = 100 ,
} ;
2005-04-16 15:20:36 -07:00
void __init ioctime_init ( void )
{
2013-12-19 22:22:23 +01:00
ioc_writeb ( RPC_LATCH & 255 , IOC_T0LTCHL ) ;
ioc_writeb ( RPC_LATCH > > 8 , IOC_T0LTCHH ) ;
2005-04-16 15:20:36 -07:00
ioc_writeb ( 0 , IOC_T0GO ) ;
}
static irqreturn_t
2006-10-06 10:53:39 -07:00
ioc_timer_interrupt ( int irq , void * dev_id )
2005-04-16 15:20:36 -07:00
{
2018-11-14 19:13:02 +00:00
ioc_time + = RPC_LATCH ;
2020-09-24 15:26:08 +02:00
legacy_timer_tick ( 1 ) ;
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}
/*
* Set up timer interrupt .
*/
2012-11-08 12:40:59 -07:00
void __init ioc_timer_init ( void )
2005-04-16 15:20:36 -07:00
{
2018-11-14 19:13:02 +00:00
WARN_ON ( clocksource_register_hz ( & ioctime_clocksource , RPC_CLOCK_FREQ ) ) ;
2005-04-16 15:20:36 -07:00
ioctime_init ( ) ;
2020-03-08 15:22:06 +01:00
if ( request_irq ( IRQ_TIMER0 , ioc_timer_interrupt , 0 , " timer " , NULL ) )
pr_err ( " Failed to request irq %d (timer) \n " , IRQ_TIMER0 ) ;
2005-04-16 15:20:36 -07:00
}