2013-07-17 12:04:57 +04:00
/*
* MOXA ART SoCs timer handling .
*
* Copyright ( C ) 2013 Jonas Jensen
*
* Jonas Jensen < jonas . jensen @ gmail . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/clk.h>
# include <linux/clockchips.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/irqreturn.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/io.h>
# include <linux/clocksource.h>
2013-07-26 18:03:38 +04:00
# include <linux/bitops.h>
2016-07-21 16:43:52 +03:00
# include <linux/slab.h>
2013-07-17 12:04:57 +04:00
# define TIMER1_BASE 0x00
# define TIMER2_BASE 0x10
# define TIMER3_BASE 0x20
# define REG_COUNT 0x0 /* writable */
# define REG_LOAD 0x4
# define REG_MATCH1 0x8
# define REG_MATCH2 0xC
# define TIMER_CR 0x30
# define TIMER_INTR_STATE 0x34
# define TIMER_INTR_MASK 0x38
/*
2016-07-21 16:43:52 +03:00
* Moxart TIMER_CR flags :
2013-07-17 12:04:57 +04:00
*
2016-07-21 16:43:52 +03:00
* MOXART_CR_ * _CLOCK 0 : PCLK , 1 : EXT1CLK
* MOXART_CR_ * _INT overflow interrupt enable bit
2013-07-17 12:04:57 +04:00
*/
2016-07-21 16:43:52 +03:00
# define MOXART_CR_1_ENABLE BIT(0)
# define MOXART_CR_1_CLOCK BIT(1)
# define MOXART_CR_1_INT BIT(2)
# define MOXART_CR_2_ENABLE BIT(3)
# define MOXART_CR_2_CLOCK BIT(4)
# define MOXART_CR_2_INT BIT(5)
# define MOXART_CR_3_ENABLE BIT(6)
# define MOXART_CR_3_CLOCK BIT(7)
# define MOXART_CR_3_INT BIT(8)
# define MOXART_CR_COUNT_UP BIT(9)
# define MOXART_TIMER1_ENABLE (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
# define MOXART_TIMER1_DISABLE (MOXART_CR_2_ENABLE)
2016-07-21 16:43:53 +03:00
/*
* The ASpeed variant of the IP block has a different layout
* for the control register
*/
# define ASPEED_CR_1_ENABLE BIT(0)
# define ASPEED_CR_1_CLOCK BIT(1)
# define ASPEED_CR_1_INT BIT(2)
# define ASPEED_CR_2_ENABLE BIT(4)
# define ASPEED_CR_2_CLOCK BIT(5)
# define ASPEED_CR_2_INT BIT(6)
# define ASPEED_CR_3_ENABLE BIT(8)
# define ASPEED_CR_3_CLOCK BIT(9)
# define ASPEED_CR_3_INT BIT(10)
# define ASPEED_TIMER1_ENABLE (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
# define ASPEED_TIMER1_DISABLE (ASPEED_CR_2_ENABLE)
2016-07-21 16:43:52 +03:00
struct moxart_timer {
void __iomem * base ;
unsigned int t1_disable_val ;
unsigned int t1_enable_val ;
unsigned int count_per_tick ;
struct clock_event_device clkevt ;
} ;
static inline struct moxart_timer * to_moxart ( struct clock_event_device * evt )
{
return container_of ( evt , struct moxart_timer , clkevt ) ;
}
2013-07-17 12:04:57 +04:00
2016-07-21 16:43:51 +03:00
static inline void moxart_disable ( struct clock_event_device * evt )
2013-07-17 12:04:57 +04:00
{
2016-07-21 16:43:52 +03:00
struct moxart_timer * timer = to_moxart ( evt ) ;
writel ( timer - > t1_disable_val , timer - > base + TIMER_CR ) ;
2016-07-21 16:43:51 +03:00
}
static inline void moxart_enable ( struct clock_event_device * evt )
{
2016-07-21 16:43:52 +03:00
struct moxart_timer * timer = to_moxart ( evt ) ;
writel ( timer - > t1_enable_val , timer - > base + TIMER_CR ) ;
2016-07-21 16:43:51 +03:00
}
static int moxart_shutdown ( struct clock_event_device * evt )
{
moxart_disable ( evt ) ;
2015-06-18 13:54:26 +03:00
return 0 ;
}
static int moxart_set_oneshot ( struct clock_event_device * evt )
{
2016-07-21 16:43:51 +03:00
moxart_disable ( evt ) ;
2016-07-21 16:43:52 +03:00
writel ( ~ 0 , to_moxart ( evt ) - > base + TIMER1_BASE + REG_LOAD ) ;
2015-06-18 13:54:26 +03:00
return 0 ;
}
static int moxart_set_periodic ( struct clock_event_device * evt )
{
2016-07-21 16:43:52 +03:00
struct moxart_timer * timer = to_moxart ( evt ) ;
moxart_disable ( evt ) ;
writel ( timer - > count_per_tick , timer - > base + TIMER1_BASE + REG_LOAD ) ;
writel ( 0 , timer - > base + TIMER1_BASE + REG_MATCH1 ) ;
2016-07-21 16:43:51 +03:00
moxart_enable ( evt ) ;
2015-06-18 13:54:26 +03:00
return 0 ;
2013-07-17 12:04:57 +04:00
}
static int moxart_clkevt_next_event ( unsigned long cycles ,
2016-07-21 16:43:51 +03:00
struct clock_event_device * evt )
2013-07-17 12:04:57 +04:00
{
2016-07-21 16:43:52 +03:00
struct moxart_timer * timer = to_moxart ( evt ) ;
2013-07-17 12:04:57 +04:00
u32 u ;
2016-07-21 16:43:51 +03:00
moxart_disable ( evt ) ;
2013-07-17 12:04:57 +04:00
2016-07-21 16:43:52 +03:00
u = readl ( timer - > base + TIMER1_BASE + REG_COUNT ) - cycles ;
writel ( u , timer - > base + TIMER1_BASE + REG_MATCH1 ) ;
2013-07-17 12:04:57 +04:00
2016-07-21 16:43:51 +03:00
moxart_enable ( evt ) ;
2013-07-17 12:04:57 +04:00
return 0 ;
}
static irqreturn_t moxart_timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * evt = dev_id ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
2016-06-06 18:57:38 +03:00
static int __init moxart_timer_init ( struct device_node * node )
2013-07-17 12:04:57 +04:00
{
int ret , irq ;
unsigned long pclk ;
struct clk * clk ;
2016-07-21 16:43:52 +03:00
struct moxart_timer * timer ;
2013-07-17 12:04:57 +04:00
2016-07-21 16:43:52 +03:00
timer = kzalloc ( sizeof ( * timer ) , GFP_KERNEL ) ;
if ( ! timer )
return - ENOMEM ;
timer - > base = of_iomap ( node , 0 ) ;
if ( ! timer - > base ) {
2016-06-06 18:57:38 +03:00
pr_err ( " %s: of_iomap failed \n " , node - > full_name ) ;
return - ENXIO ;
}
2013-07-17 12:04:57 +04:00
irq = irq_of_parse_and_map ( node , 0 ) ;
2016-06-06 18:57:38 +03:00
if ( irq < = 0 ) {
pr_err ( " %s: irq_of_parse_and_map failed \n " , node - > full_name ) ;
return - EINVAL ;
}
2013-07-17 12:04:57 +04:00
clk = of_clk_get ( node , 0 ) ;
2016-06-06 18:57:38 +03:00
if ( IS_ERR ( clk ) ) {
pr_err ( " %s: of_clk_get failed \n " , node - > full_name ) ;
return PTR_ERR ( clk ) ;
}
2013-07-17 12:04:57 +04:00
pclk = clk_get_rate ( clk ) ;
2016-07-21 16:43:52 +03:00
if ( of_device_is_compatible ( node , " moxa,moxart-timer " ) ) {
timer - > t1_enable_val = MOXART_TIMER1_ENABLE ;
timer - > t1_disable_val = MOXART_TIMER1_DISABLE ;
2016-07-21 16:43:53 +03:00
} else if ( of_device_is_compatible ( node , " aspeed,ast2400-timer " ) ) {
timer - > t1_enable_val = ASPEED_TIMER1_ENABLE ;
timer - > t1_disable_val = ASPEED_TIMER1_DISABLE ;
2016-09-08 15:25:40 +03:00
} else {
pr_err ( " %s: unknown platform \n " , node - > full_name ) ;
return - EINVAL ;
}
2016-07-21 16:43:52 +03:00
timer - > count_per_tick = DIV_ROUND_CLOSEST ( pclk , HZ ) ;
timer - > clkevt . name = node - > name ;
timer - > clkevt . rating = 200 ;
timer - > clkevt . features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT ;
timer - > clkevt . set_state_shutdown = moxart_shutdown ;
timer - > clkevt . set_state_periodic = moxart_set_periodic ;
timer - > clkevt . set_state_oneshot = moxart_set_oneshot ;
timer - > clkevt . tick_resume = moxart_set_oneshot ;
timer - > clkevt . set_next_event = moxart_clkevt_next_event ;
timer - > clkevt . cpumask = cpumask_of ( 0 ) ;
timer - > clkevt . irq = irq ;
ret = clocksource_mmio_init ( timer - > base + TIMER2_BASE + REG_COUNT ,
2016-06-06 18:57:38 +03:00
" moxart_timer " , pclk , 200 , 32 ,
clocksource_mmio_readl_down ) ;
if ( ret ) {
pr_err ( " %s: clocksource_mmio_init failed \n " , node - > full_name ) ;
return ret ;
}
2013-07-17 12:04:57 +04:00
2016-09-08 15:17:00 +03:00
ret = request_irq ( irq , moxart_timer_interrupt , IRQF_TIMER ,
node - > name , & timer - > clkevt ) ;
2016-07-21 16:43:52 +03:00
if ( ret ) {
pr_err ( " %s: setup_irq failed \n " , node - > full_name ) ;
return ret ;
}
2013-07-17 12:04:57 +04:00
2016-07-21 16:43:53 +03:00
/* Clear match registers */
writel ( 0 , timer - > base + TIMER1_BASE + REG_MATCH1 ) ;
writel ( 0 , timer - > base + TIMER1_BASE + REG_MATCH2 ) ;
writel ( 0 , timer - > base + TIMER2_BASE + REG_MATCH1 ) ;
writel ( 0 , timer - > base + TIMER2_BASE + REG_MATCH2 ) ;
/*
* Start timer 2 rolling as our main wall clock source , keep timer 1
* disabled
*/
writel ( 0 , timer - > base + TIMER_CR ) ;
2016-07-21 16:43:52 +03:00
writel ( ~ 0 , timer - > base + TIMER2_BASE + REG_LOAD ) ;
writel ( timer - > t1_disable_val , timer - > base + TIMER_CR ) ;
2013-07-17 12:04:57 +04:00
/*
* documentation is not publicly available :
* min_delta / max_delta obtained by trial - and - error ,
* max_delta 0xfffffffe should be ok because count
* register size is u32
*/
2016-07-21 16:43:52 +03:00
clockevents_config_and_register ( & timer - > clkevt , pclk , 0x4 , 0xfffffffe ) ;
2016-06-06 18:57:38 +03:00
return 0 ;
2013-07-17 12:04:57 +04:00
}
2016-06-07 01:27:44 +03:00
CLOCKSOURCE_OF_DECLARE ( moxart , " moxa,moxart-timer " , moxart_timer_init ) ;
2016-07-21 16:43:53 +03:00
CLOCKSOURCE_OF_DECLARE ( aspeed , " aspeed,ast2400-timer " , moxart_timer_init ) ;