2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-12-03 05:55:38 +03:00
/*
* linux / arch / arm / mach - w90x900 / time . c
*
* Based on linux / arch / arm / plat - s3c24xx / time . c by Ben Dooks
*
2009-08-14 18:36:44 +04:00
* Copyright ( c ) 2009 Nuvoton technology corporation
2008-12-03 05:55:38 +03:00
* All rights reserved .
*
* Wan ZongShun < mcuos . com @ gmail . com >
*/
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/err.h>
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/leds.h>
2009-08-14 18:36:44 +04:00
# include <linux/clocksource.h>
# include <linux/clockchips.h>
2008-12-03 05:55:38 +03:00
# include <asm/mach-types.h>
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
# include <mach/map.h>
2015-01-30 12:45:33 +03:00
# include "regs-timer.h"
2008-12-03 05:55:38 +03:00
2011-11-07 22:02:39 +04:00
# include "nuc9xx.h"
2009-08-14 18:36:44 +04:00
# define RESETINT 0x1f
# define PERIOD (0x01 << 27)
# define ONESHOT (0x00 << 27)
# define COUNTEN (0x01 << 30)
# define INTEN (0x01 << 29)
# define TICKS_PER_SEC 100
# define PRESCALE 0x63 /* Divider = prescale + 1 */
2009-12-31 17:57:53 +03:00
# define TDR_SHIFT 24
static unsigned int timer0_load ;
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
static int nuc900_clockevent_shutdown ( struct clock_event_device * evt )
2008-12-03 05:55:38 +03:00
{
2015-02-27 11:09:52 +03:00
unsigned int val = __raw_readl ( REG_TCSR0 ) & ~ ( 0x03 < < 27 ) ;
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
__raw_writel ( val , REG_TCSR0 ) ;
return 0 ;
}
static int nuc900_clockevent_set_oneshot ( struct clock_event_device * evt )
{
unsigned int val = __raw_readl ( REG_TCSR0 ) & ~ ( 0x03 < < 27 ) ;
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
val | = ( ONESHOT | COUNTEN | INTEN | PRESCALE ) ;
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
__raw_writel ( val , REG_TCSR0 ) ;
return 0 ;
}
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
static int nuc900_clockevent_set_periodic ( struct clock_event_device * evt )
{
unsigned int val = __raw_readl ( REG_TCSR0 ) & ~ ( 0x03 < < 27 ) ;
2009-08-14 18:36:44 +04:00
2015-02-27 11:09:52 +03:00
__raw_writel ( timer0_load , REG_TICR0 ) ;
val | = ( PERIOD | COUNTEN | INTEN | PRESCALE ) ;
2009-08-14 18:36:44 +04:00
__raw_writel ( val , REG_TCSR0 ) ;
2015-02-27 11:09:52 +03:00
return 0 ;
2009-08-14 18:36:44 +04:00
}
2009-08-21 10:07:46 +04:00
static int nuc900_clockevent_setnextevent ( unsigned long evt ,
2009-08-14 18:36:44 +04:00
struct clock_event_device * clk )
{
unsigned int val ;
__raw_writel ( evt , REG_TICR0 ) ;
val = __raw_readl ( REG_TCSR0 ) ;
val | = ( COUNTEN | INTEN | PRESCALE ) ;
__raw_writel ( val , REG_TCSR0 ) ;
2008-12-03 05:55:38 +03:00
return 0 ;
}
2009-08-21 10:07:46 +04:00
static struct clock_event_device nuc900_clockevent_device = {
2015-02-27 11:09:52 +03:00
. name = " nuc900-timer0 " ,
. features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT ,
. set_state_shutdown = nuc900_clockevent_shutdown ,
. set_state_periodic = nuc900_clockevent_set_periodic ,
. set_state_oneshot = nuc900_clockevent_set_oneshot ,
. tick_resume = nuc900_clockevent_shutdown ,
. set_next_event = nuc900_clockevent_setnextevent ,
. rating = 300 ,
2009-08-14 18:36:44 +04:00
} ;
2008-12-03 05:55:38 +03:00
/*IRQ handler for the timer*/
2009-08-21 10:07:46 +04:00
static irqreturn_t nuc900_timer0_interrupt ( int irq , void * dev_id )
2008-12-03 05:55:38 +03:00
{
2009-08-21 10:07:46 +04:00
struct clock_event_device * evt = & nuc900_clockevent_device ;
2009-08-14 18:36:44 +04:00
2008-12-03 05:55:38 +03:00
__raw_writel ( 0x01 , REG_TISR ) ; /* clear TIF0 */
2009-08-14 18:36:44 +04:00
evt - > event_handler ( evt ) ;
2008-12-03 05:55:38 +03:00
return IRQ_HANDLED ;
}
2009-08-21 10:07:46 +04:00
static struct irqaction nuc900_timer0_irq = {
. name = " nuc900-timer0 " ,
2014-03-05 01:11:56 +04:00
. flags = IRQF_TIMER | IRQF_IRQPOLL ,
2009-08-21 10:07:46 +04:00
. handler = nuc900_timer0_interrupt ,
2008-12-03 05:55:38 +03:00
} ;
2009-12-31 17:57:53 +03:00
static void __init nuc900_clockevents_init ( void )
2009-08-14 18:36:44 +04:00
{
2009-12-31 17:57:53 +03:00
unsigned int rate ;
struct clk * clk = clk_get ( NULL , " timer0 " ) ;
BUG_ON ( IS_ERR ( clk ) ) ;
__raw_writel ( 0x00 , REG_TCSR0 ) ;
clk_enable ( clk ) ;
rate = clk_get_rate ( clk ) / ( PRESCALE + 1 ) ;
timer0_load = ( rate / TICKS_PER_SEC ) ;
__raw_writel ( RESETINT , REG_TISR ) ;
setup_irq ( IRQ_TIMER0 , & nuc900_timer0_irq ) ;
2009-08-21 10:07:46 +04:00
nuc900_clockevent_device . cpumask = cpumask_of ( 0 ) ;
2013-01-12 15:50:05 +04:00
clockevents_config_and_register ( & nuc900_clockevent_device , rate ,
0xf , 0xffffffff ) ;
2009-08-14 18:36:44 +04:00
}
2009-12-31 17:57:53 +03:00
static void __init nuc900_clocksource_init ( void )
2008-12-03 05:55:38 +03:00
{
2009-08-14 18:36:44 +04:00
unsigned int val ;
2009-12-31 17:57:53 +03:00
unsigned int rate ;
struct clk * clk = clk_get ( NULL , " timer1 " ) ;
BUG_ON ( IS_ERR ( clk ) ) ;
__raw_writel ( 0x00 , REG_TCSR1 ) ;
clk_enable ( clk ) ;
rate = clk_get_rate ( clk ) / ( PRESCALE + 1 ) ;
2009-08-14 18:36:44 +04:00
__raw_writel ( 0xffffffff , REG_TICR1 ) ;
val = __raw_readl ( REG_TCSR1 ) ;
2009-12-31 17:57:53 +03:00
val | = ( COUNTEN | PERIOD | PRESCALE ) ;
2009-08-14 18:36:44 +04:00
__raw_writel ( val , REG_TCSR1 ) ;
2011-05-08 18:34:39 +04:00
clocksource_mmio_init ( REG_TDR1 , " nuc900-timer1 " , rate , 200 ,
TDR_SHIFT , clocksource_mmio_readl_down ) ;
2009-08-14 18:36:44 +04:00
}
2012-11-08 23:40:59 +04:00
void __init nuc900_timer_init ( void )
2009-08-14 18:36:44 +04:00
{
2009-12-31 17:57:53 +03:00
nuc900_clocksource_init ( ) ;
nuc900_clockevents_init ( ) ;
2008-12-03 05:55:38 +03:00
}