2007-07-30 02:38:47 +01:00
/*
* arch / arm / mach - at91 / at91x40_time . c
*
* ( C ) Copyright 2007 , Greg Ungerer < gerg @ snapgear . com >
*
* 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
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/time.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2007-07-30 02:38:47 +01:00
# include <asm/mach/time.h>
2012-10-30 06:45:13 +08:00
# include "at91_tc.h"
2007-07-30 02:38:47 +01:00
2012-02-05 20:35:39 +08:00
# define at91_tc_read(field) \
2012-09-14 20:10:19 +00:00
__raw_readl ( AT91_IO_P2V ( AT91_TC ) + field )
2012-02-05 20:35:39 +08:00
# define at91_tc_write(field, value) \
2013-04-07 16:49:59 +02:00
__raw_writel ( value , AT91_IO_P2V ( AT91_TC ) + field )
2012-02-05 20:35:39 +08:00
2007-07-30 02:38:47 +01:00
/*
* 3 counter / timer units present .
*/
# define AT91_TC_CLK0BASE 0
# define AT91_TC_CLK1BASE 0x40
# define AT91_TC_CLK2BASE 0x80
2012-11-08 11:51:58 -07:00
static u32 at91x40_gettimeoffset ( void )
2007-07-30 02:38:47 +01:00
{
2012-11-08 11:51:58 -07:00
return ( at91_tc_read ( AT91_TC_CLK1BASE + AT91_TC_CV ) * 1000000 /
( AT91X40_MASTER_CLOCK / 128 ) ) * 1000 ;
2007-07-30 02:38:47 +01:00
}
static irqreturn_t at91x40_timer_interrupt ( int irq , void * dev_id )
{
2012-02-05 20:35:39 +08:00
at91_tc_read ( AT91_TC_CLK1BASE + AT91_TC_SR ) ;
2007-07-30 02:38:47 +01:00
timer_tick ( ) ;
return IRQ_HANDLED ;
}
static struct irqaction at91x40_timer_irq = {
. name = " at91_tick " ,
2013-09-04 06:54:39 +02:00
. flags = IRQF_TIMER ,
2007-07-30 02:38:47 +01:00
. handler = at91x40_timer_interrupt
} ;
void __init at91x40_timer_init ( void )
{
unsigned int v ;
2012-11-08 11:51:58 -07:00
arch_gettimeoffset = at91x40_gettimeoffset ;
2012-02-05 20:35:39 +08:00
at91_tc_write ( AT91_TC_BCR , 0 ) ;
v = at91_tc_read ( AT91_TC_BMR ) ;
2007-07-30 02:38:47 +01:00
v = ( v & ~ AT91_TC_TC1XC1S ) | AT91_TC_TC1XC1S_NONE ;
2012-02-05 20:35:39 +08:00
at91_tc_write ( AT91_TC_BMR , v ) ;
2007-07-30 02:38:47 +01:00
2012-02-05 20:35:39 +08:00
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_CCR , AT91_TC_CLKDIS ) ;
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_CMR , ( AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG ) ) ;
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_IDR , 0xffffffff ) ;
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_RC , ( AT91X40_MASTER_CLOCK / 128 ) / HZ - 1 ) ;
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_IER , ( 1 < < 4 ) ) ;
2007-07-30 02:38:47 +01:00
setup_irq ( AT91X40_ID_TC1 , & at91x40_timer_irq ) ;
2012-02-05 20:35:39 +08:00
at91_tc_write ( AT91_TC_CLK1BASE + AT91_TC_CCR , ( AT91_TC_SWTRG | AT91_TC_CLKEN ) ) ;
2007-07-30 02:38:47 +01:00
}