2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-10 14:10:56 +04:00
/*
* Keystone broadcast clock - event
*
* Copyright 2013 Texas Instruments , Inc .
*
* Author : Ivan Khoronzhuk < ivan . khoronzhuk @ ti . com >
*/
# include <linux/clk.h>
# include <linux/clockchips.h>
# include <linux/clocksource.h>
# include <linux/interrupt.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# define TIMER_NAME "timer-keystone"
/* Timer register offsets */
# define TIM12 0x10
# define TIM34 0x14
# define PRD12 0x18
# define PRD34 0x1c
# define TCR 0x20
# define TGCR 0x24
# define INTCTLSTAT 0x44
/* Timer register bitfields */
# define TCR_ENAMODE_MASK 0xC0
# define TCR_ENAMODE_ONESHOT_MASK 0x40
# define TCR_ENAMODE_PERIODIC_MASK 0x80
# define TGCR_TIM_UNRESET_MASK 0x03
# define INTCTLSTAT_ENINT_MASK 0x01
/**
* struct keystone_timer : holds timer ' s data
* @ base : timer memory base address
* @ hz_period : cycles per HZ period
* @ event_dev : event device based on timer
*/
static struct keystone_timer {
void __iomem * base ;
unsigned long hz_period ;
struct clock_event_device event_dev ;
} timer ;
static inline u32 keystone_timer_readl ( unsigned long rg )
{
return readl_relaxed ( timer . base + rg ) ;
}
static inline void keystone_timer_writel ( u32 val , unsigned long rg )
{
writel_relaxed ( val , timer . base + rg ) ;
}
/**
* keystone_timer_barrier : write memory barrier
* use explicit barrier to avoid using readl / writel non relaxed function
* variants , because in our case non relaxed variants hide the true places
* where barrier is needed .
*/
static inline void keystone_timer_barrier ( void )
{
__iowmb ( ) ;
}
/**
* keystone_timer_config : configures timer to work in oneshot / periodic modes .
2015-06-18 13:54:48 +03:00
* @ mask : mask of the mode to configure
2014-02-10 14:10:56 +04:00
* @ period : cycles number to configure for
*/
2015-06-18 13:54:48 +03:00
static int keystone_timer_config ( u64 period , int mask )
2014-02-10 14:10:56 +04:00
{
u32 tcr ;
u32 off ;
tcr = keystone_timer_readl ( TCR ) ;
off = tcr & ~ ( TCR_ENAMODE_MASK ) ;
/* set enable mode */
2015-06-18 13:54:48 +03:00
tcr | = mask ;
2014-02-10 14:10:56 +04:00
/* disable timer */
keystone_timer_writel ( off , TCR ) ;
/* here we have to be sure the timer has been disabled */
keystone_timer_barrier ( ) ;
/* reset counter to zero, set new period */
keystone_timer_writel ( 0 , TIM12 ) ;
keystone_timer_writel ( 0 , TIM34 ) ;
keystone_timer_writel ( period & 0xffffffff , PRD12 ) ;
keystone_timer_writel ( period > > 32 , PRD34 ) ;
/*
* enable timer
* here we have to be sure that CNTLO , CNTHI , PRDLO , PRDHI registers
* have been written .
*/
keystone_timer_barrier ( ) ;
keystone_timer_writel ( tcr , TCR ) ;
return 0 ;
}
static void keystone_timer_disable ( void )
{
u32 tcr ;
tcr = keystone_timer_readl ( TCR ) ;
/* disable timer */
tcr & = ~ ( TCR_ENAMODE_MASK ) ;
keystone_timer_writel ( tcr , TCR ) ;
}
static irqreturn_t keystone_timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * evt = dev_id ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
static int keystone_set_next_event ( unsigned long cycles ,
struct clock_event_device * evt )
{
2015-06-18 13:54:48 +03:00
return keystone_timer_config ( cycles , TCR_ENAMODE_ONESHOT_MASK ) ;
2014-02-10 14:10:56 +04:00
}
2015-06-18 13:54:48 +03:00
static int keystone_shutdown ( struct clock_event_device * evt )
2014-02-10 14:10:56 +04:00
{
2015-06-18 13:54:48 +03:00
keystone_timer_disable ( ) ;
return 0 ;
}
static int keystone_set_periodic ( struct clock_event_device * evt )
{
keystone_timer_config ( timer . hz_period , TCR_ENAMODE_PERIODIC_MASK ) ;
return 0 ;
2014-02-10 14:10:56 +04:00
}
2016-06-07 00:27:44 +03:00
static int __init keystone_timer_init ( struct device_node * np )
2014-02-10 14:10:56 +04:00
{
struct clock_event_device * event_dev = & timer . event_dev ;
unsigned long rate ;
struct clk * clk ;
int irq , error ;
irq = irq_of_parse_and_map ( np , 0 ) ;
2015-09-20 17:00:35 +03:00
if ( ! irq ) {
2014-02-10 14:10:56 +04:00
pr_err ( " %s: failed to map interrupts \n " , __func__ ) ;
2016-06-07 00:27:44 +03:00
return - EINVAL ;
2014-02-10 14:10:56 +04:00
}
timer . base = of_iomap ( np , 0 ) ;
if ( ! timer . base ) {
pr_err ( " %s: failed to map registers \n " , __func__ ) ;
2016-06-07 00:27:44 +03:00
return - ENXIO ;
2014-02-10 14:10:56 +04:00
}
clk = of_clk_get ( np , 0 ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " %s: failed to get clock \n " , __func__ ) ;
iounmap ( timer . base ) ;
2016-06-07 00:27:44 +03:00
return PTR_ERR ( clk ) ;
2014-02-10 14:10:56 +04:00
}
error = clk_prepare_enable ( clk ) ;
if ( error ) {
pr_err ( " %s: failed to enable clock \n " , __func__ ) ;
goto err ;
}
rate = clk_get_rate ( clk ) ;
/* disable, use internal clock source */
keystone_timer_writel ( 0 , TCR ) ;
/* here we have to be sure the timer has been disabled */
keystone_timer_barrier ( ) ;
/* reset timer as 64-bit, no pre-scaler, plus features are disabled */
keystone_timer_writel ( 0 , TGCR ) ;
/* unreset timer */
2014-02-18 22:29:28 +04:00
keystone_timer_writel ( TGCR_TIM_UNRESET_MASK , TGCR ) ;
2014-02-10 14:10:56 +04:00
/* init counter to zero */
keystone_timer_writel ( 0 , TIM12 ) ;
keystone_timer_writel ( 0 , TIM34 ) ;
timer . hz_period = DIV_ROUND_UP ( rate , HZ ) ;
/* enable timer interrupts */
keystone_timer_writel ( INTCTLSTAT_ENINT_MASK , INTCTLSTAT ) ;
error = request_irq ( irq , keystone_timer_interrupt , IRQF_TIMER ,
TIMER_NAME , event_dev ) ;
if ( error ) {
pr_err ( " %s: failed to setup irq \n " , __func__ ) ;
goto err ;
}
/* setup clockevent */
event_dev - > features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ;
event_dev - > set_next_event = keystone_set_next_event ;
2015-06-18 13:54:48 +03:00
event_dev - > set_state_shutdown = keystone_shutdown ;
event_dev - > set_state_periodic = keystone_set_periodic ;
event_dev - > set_state_oneshot = keystone_shutdown ;
2018-07-11 14:24:22 +03:00
event_dev - > cpumask = cpu_possible_mask ;
2014-02-10 14:10:56 +04:00
event_dev - > owner = THIS_MODULE ;
event_dev - > name = TIMER_NAME ;
event_dev - > irq = irq ;
clockevents_config_and_register ( event_dev , rate , 1 , ULONG_MAX ) ;
pr_info ( " keystone timer clock @%lu Hz \n " , rate ) ;
2016-06-07 00:27:44 +03:00
return 0 ;
2014-02-10 14:10:56 +04:00
err :
clk_put ( clk ) ;
iounmap ( timer . base ) ;
2016-06-07 00:27:44 +03:00
return error ;
2014-02-10 14:10:56 +04:00
}
2017-05-26 17:56:11 +03:00
TIMER_OF_DECLARE ( keystone_timer , " ti,keystone-timer " ,
2016-06-07 00:27:44 +03:00
keystone_timer_init ) ;