2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-06-20 21:47:27 +04:00
/*
2013-03-27 15:05:28 +04:00
* This file contains driver for the Cadence Triple Timer Counter Rev 06
2011-06-20 21:47:27 +04:00
*
2013-03-20 13:15:28 +04:00
* Copyright ( C ) 2011 - 2013 Xilinx
2011-06-20 21:47:27 +04:00
*
* based on arch / mips / kernel / time . c timer driver
*/
2013-03-20 13:15:28 +04:00
# include <linux/clk.h>
2011-06-20 21:47:27 +04:00
# include <linux/interrupt.h>
# include <linux/clockchips.h>
2017-06-11 08:22:10 +03:00
# include <linux/clocksource.h>
2012-10-31 23:56:14 +04:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2023-07-14 20:44:09 +03:00
# include <linux/platform_device.h>
2012-10-31 23:56:14 +04:00
# include <linux/slab.h>
2013-07-08 20:51:38 +04:00
# include <linux/sched_clock.h>
2019-11-07 13:36:28 +03:00
# include <linux/module.h>
# include <linux/of_platform.h>
2011-06-20 21:47:27 +04:00
2013-03-20 13:15:28 +04:00
/*
2014-09-29 03:50:05 +04:00
* This driver configures the 2 16 / 32 - bit count - up timers as follows :
2013-03-20 13:15:28 +04:00
*
* T1 : Timer 1 , clocksource for generic timekeeping
* T2 : Timer 2 , clockevent source for hrtimers
* T3 : Timer 3 , < unused >
*
* The input frequency to the timer module for emulation is 2.5 MHz which is
* common to all the timer channels ( T1 , T2 , and T3 ) . With a pre - scaler of 32 ,
* the timers are clocked at 78.125 KHz ( 12.8 us resolution ) .
* The input frequency to the timer module in silicon is configurable and
* obtained from device tree . The pre - scaler of 32 is used .
*/
2011-06-20 21:47:27 +04:00
/*
* Timer Register Offset Definitions of Timer 1 , Increment base address by 4
* and use same offsets for Timer 2
*/
2013-03-27 15:05:28 +04:00
# define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */
# define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */
# define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */
# define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */
# define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */
# define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */
2012-12-19 22:18:36 +04:00
2013-03-27 15:05:28 +04:00
# define TTC_CNT_CNTRL_DISABLE_MASK 0x1
2011-06-20 21:47:27 +04:00
2013-05-13 21:46:38 +04:00
# define TTC_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */
2014-02-20 03:14:42 +04:00
# define TTC_CLK_CNTRL_PSV_MASK 0x1e
# define TTC_CLK_CNTRL_PSV_SHIFT 1
2013-05-13 21:46:38 +04:00
2012-12-19 22:18:41 +04:00
/*
* Setup the timers to use pre - scaling , using a fixed value for now that will
2012-10-31 23:56:14 +04:00
* work across most input frequency , but it may need to be more dynamic
*/
# define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
# define PRESCALE 2048 /* The exponent must match this */
# define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1)
# define CLK_CNTRL_PRESCALE_EN 1
2013-03-20 13:15:28 +04:00
# define CNT_CNTRL_RESET (1 << 4)
2011-06-20 21:47:27 +04:00
2014-02-20 03:14:42 +04:00
# define MAX_F_ERR 50
2011-06-20 21:47:27 +04:00
/**
2013-03-27 15:05:28 +04:00
* struct ttc_timer - This definition defines local timer structure
2011-06-20 21:47:27 +04:00
*
* @ base_addr : Base address of timer
2013-11-27 05:04:50 +04:00
* @ freq : Timer input clock frequency
2013-03-20 13:15:28 +04:00
* @ clk : Associated clock source
* @ clk_rate_change_nb Notifier block for clock rate changes
*/
2013-03-27 15:05:28 +04:00
struct ttc_timer {
2013-03-20 13:15:28 +04:00
void __iomem * base_addr ;
2013-11-27 05:04:50 +04:00
unsigned long freq ;
2013-03-20 13:15:28 +04:00
struct clk * clk ;
struct notifier_block clk_rate_change_nb ;
2012-10-31 23:56:14 +04:00
} ;
2013-03-27 15:05:28 +04:00
# define to_ttc_timer(x) \
container_of ( x , struct ttc_timer , clk_rate_change_nb )
2013-03-20 13:15:28 +04:00
2013-03-27 15:05:28 +04:00
struct ttc_timer_clocksource {
2014-02-20 03:14:42 +04:00
u32 scale_clk_ctrl_reg_old ;
u32 scale_clk_ctrl_reg_new ;
2013-03-27 15:05:28 +04:00
struct ttc_timer ttc ;
2012-10-31 23:56:14 +04:00
struct clocksource cs ;
2011-06-20 21:47:27 +04:00
} ;
2013-03-27 15:05:28 +04:00
# define to_ttc_timer_clksrc(x) \
container_of ( x , struct ttc_timer_clocksource , cs )
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
struct ttc_timer_clockevent {
struct ttc_timer ttc ;
2012-10-31 23:56:14 +04:00
struct clock_event_device ce ;
} ;
2013-03-27 15:05:28 +04:00
# define to_ttc_timer_clkevent(x) \
container_of ( x , struct ttc_timer_clockevent , ce )
2011-06-20 21:47:27 +04:00
2013-07-08 20:51:38 +04:00
static void __iomem * ttc_sched_clock_val_reg ;
2011-06-20 21:47:27 +04:00
/**
2013-03-27 15:05:28 +04:00
* ttc_set_interval - Set the timer interval value
2011-06-20 21:47:27 +04:00
*
* @ timer : Pointer to the timer instance
* @ cycles : Timer interval ticks
* */
2013-03-27 15:05:28 +04:00
static void ttc_set_interval ( struct ttc_timer * timer ,
2011-06-20 21:47:27 +04:00
unsigned long cycles )
{
u32 ctrl_reg ;
/* Disable the counter, set the counter value and re-enable counter */
2014-04-11 17:39:29 +04:00
ctrl_reg = readl_relaxed ( timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
2013-03-27 15:05:28 +04:00
ctrl_reg | = TTC_CNT_CNTRL_DISABLE_MASK ;
2014-04-11 17:39:29 +04:00
writel_relaxed ( ctrl_reg , timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
2011-06-20 21:47:27 +04:00
2014-04-11 17:39:29 +04:00
writel_relaxed ( cycles , timer - > base_addr + TTC_INTR_VAL_OFFSET ) ;
2011-06-20 21:47:27 +04:00
2012-12-19 22:18:41 +04:00
/*
* Reset the counter ( 0x10 ) so that it starts from 0 , one - shot
* mode makes this needed for timing to be right .
*/
2012-10-31 23:56:14 +04:00
ctrl_reg | = CNT_CNTRL_RESET ;
2013-03-27 15:05:28 +04:00
ctrl_reg & = ~ TTC_CNT_CNTRL_DISABLE_MASK ;
2014-04-11 17:39:29 +04:00
writel_relaxed ( ctrl_reg , timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
2011-06-20 21:47:27 +04:00
}
/**
2013-03-27 15:05:28 +04:00
* ttc_clock_event_interrupt - Clock event timer interrupt handler
2011-06-20 21:47:27 +04:00
*
* @ irq : IRQ number of the Timer
2013-03-27 15:05:28 +04:00
* @ dev_id : void pointer to the ttc_timer instance
2011-06-20 21:47:27 +04:00
*
* returns : Always IRQ_HANDLED - success
* */
2013-03-27 15:05:28 +04:00
static irqreturn_t ttc_clock_event_interrupt ( int irq , void * dev_id )
2011-06-20 21:47:27 +04:00
{
2013-03-27 15:05:28 +04:00
struct ttc_timer_clockevent * ttce = dev_id ;
struct ttc_timer * timer = & ttce - > ttc ;
2011-06-20 21:47:27 +04:00
/* Acknowledge the interrupt and call event handler */
2014-04-11 17:39:29 +04:00
readl_relaxed ( timer - > base_addr + TTC_ISR_OFFSET ) ;
2011-06-20 21:47:27 +04:00
2013-03-27 15:05:28 +04:00
ttce - > ce . event_handler ( & ttce - > ce ) ;
2011-06-20 21:47:27 +04:00
return IRQ_HANDLED ;
}
/**
2013-03-27 15:05:28 +04:00
* __ttc_clocksource_read - Reads the timer counter register
2011-06-20 21:47:27 +04:00
*
* returns : Current timer counter register value
* */
2016-12-21 22:32:01 +03:00
static u64 __ttc_clocksource_read ( struct clocksource * cs )
2011-06-20 21:47:27 +04:00
{
2013-03-27 15:05:28 +04:00
struct ttc_timer * timer = & to_ttc_timer_clksrc ( cs ) - > ttc ;
2011-06-20 21:47:27 +04:00
2016-12-21 22:32:01 +03:00
return ( u64 ) readl_relaxed ( timer - > base_addr +
2013-03-27 15:05:28 +04:00
TTC_COUNT_VAL_OFFSET ) ;
2011-06-20 21:47:27 +04:00
}
2013-11-20 03:47:32 +04:00
static u64 notrace ttc_sched_clock_read ( void )
2013-07-08 20:51:38 +04:00
{
2014-04-11 17:39:29 +04:00
return readl_relaxed ( ttc_sched_clock_val_reg ) ;
2013-07-08 20:51:38 +04:00
}
2011-06-20 21:47:27 +04:00
/**
2013-03-27 15:05:28 +04:00
* ttc_set_next_event - Sets the time interval for next event
2011-06-20 21:47:27 +04:00
*
* @ cycles : Timer interval ticks
* @ evt : Address of clock event instance
*
* returns : Always 0 - success
* */
2013-03-27 15:05:28 +04:00
static int ttc_set_next_event ( unsigned long cycles ,
2011-06-20 21:47:27 +04:00
struct clock_event_device * evt )
{
2013-03-27 15:05:28 +04:00
struct ttc_timer_clockevent * ttce = to_ttc_timer_clkevent ( evt ) ;
struct ttc_timer * timer = & ttce - > ttc ;
2011-06-20 21:47:27 +04:00
2013-03-27 15:05:28 +04:00
ttc_set_interval ( timer , cycles ) ;
2011-06-20 21:47:27 +04:00
return 0 ;
}
/**
2015-06-18 13:54:16 +03:00
* ttc_set_ { shutdown | oneshot | periodic } - Sets the state of timer
2011-06-20 21:47:27 +04:00
*
* @ evt : Address of clock event instance
* */
2015-06-18 13:54:16 +03:00
static int ttc_shutdown ( struct clock_event_device * evt )
2011-06-20 21:47:27 +04:00
{
2013-03-27 15:05:28 +04:00
struct ttc_timer_clockevent * ttce = to_ttc_timer_clkevent ( evt ) ;
struct ttc_timer * timer = & ttce - > ttc ;
2011-06-20 21:47:27 +04:00
u32 ctrl_reg ;
2015-06-18 13:54:16 +03:00
ctrl_reg = readl_relaxed ( timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
ctrl_reg | = TTC_CNT_CNTRL_DISABLE_MASK ;
writel_relaxed ( ctrl_reg , timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
return 0 ;
}
static int ttc_set_periodic ( struct clock_event_device * evt )
{
struct ttc_timer_clockevent * ttce = to_ttc_timer_clkevent ( evt ) ;
struct ttc_timer * timer = & ttce - > ttc ;
ttc_set_interval ( timer ,
DIV_ROUND_CLOSEST ( ttce - > ttc . freq , PRESCALE * HZ ) ) ;
return 0 ;
}
static int ttc_resume ( struct clock_event_device * evt )
{
struct ttc_timer_clockevent * ttce = to_ttc_timer_clkevent ( evt ) ;
struct ttc_timer * timer = & ttce - > ttc ;
u32 ctrl_reg ;
ctrl_reg = readl_relaxed ( timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
ctrl_reg & = ~ TTC_CNT_CNTRL_DISABLE_MASK ;
writel_relaxed ( ctrl_reg , timer - > base_addr + TTC_CNT_CNTRL_OFFSET ) ;
return 0 ;
2011-06-20 21:47:27 +04:00
}
2013-03-27 15:05:28 +04:00
static int ttc_rate_change_clocksource_cb ( struct notifier_block * nb ,
2013-03-20 13:15:28 +04:00
unsigned long event , void * data )
{
struct clk_notifier_data * ndata = data ;
2013-03-27 15:05:28 +04:00
struct ttc_timer * ttc = to_ttc_timer ( nb ) ;
struct ttc_timer_clocksource * ttccs = container_of ( ttc ,
struct ttc_timer_clocksource , ttc ) ;
2013-03-20 13:15:28 +04:00
switch ( event ) {
2014-02-20 03:14:42 +04:00
case PRE_RATE_CHANGE :
{
u32 psv ;
unsigned long factor , rate_low , rate_high ;
if ( ndata - > new_rate > ndata - > old_rate ) {
factor = DIV_ROUND_CLOSEST ( ndata - > new_rate ,
ndata - > old_rate ) ;
rate_low = ndata - > old_rate ;
rate_high = ndata - > new_rate ;
} else {
factor = DIV_ROUND_CLOSEST ( ndata - > old_rate ,
ndata - > new_rate ) ;
rate_low = ndata - > new_rate ;
rate_high = ndata - > old_rate ;
}
if ( ! is_power_of_2 ( factor ) )
return NOTIFY_BAD ;
if ( abs ( rate_high - ( factor * rate_low ) ) > MAX_F_ERR )
return NOTIFY_BAD ;
factor = __ilog2_u32 ( factor ) ;
2013-03-20 13:15:28 +04:00
/*
2014-02-20 03:14:42 +04:00
* store timer clock ctrl register so we can restore it in case
* of an abort .
2013-03-20 13:15:28 +04:00
*/
2014-02-20 03:14:42 +04:00
ttccs - > scale_clk_ctrl_reg_old =
2014-04-11 17:39:29 +04:00
readl_relaxed ( ttccs - > ttc . base_addr +
TTC_CLK_CNTRL_OFFSET ) ;
2014-02-20 03:14:42 +04:00
psv = ( ttccs - > scale_clk_ctrl_reg_old &
TTC_CLK_CNTRL_PSV_MASK ) > >
TTC_CLK_CNTRL_PSV_SHIFT ;
if ( ndata - > new_rate < ndata - > old_rate )
psv - = factor ;
else
psv + = factor ;
/* prescaler within legal range? */
if ( psv & ~ ( TTC_CLK_CNTRL_PSV_MASK > > TTC_CLK_CNTRL_PSV_SHIFT ) )
return NOTIFY_BAD ;
ttccs - > scale_clk_ctrl_reg_new = ttccs - > scale_clk_ctrl_reg_old &
~ TTC_CLK_CNTRL_PSV_MASK ;
ttccs - > scale_clk_ctrl_reg_new | = psv < < TTC_CLK_CNTRL_PSV_SHIFT ;
/* scale down: adjust divider in post-change notification */
if ( ndata - > new_rate < ndata - > old_rate )
return NOTIFY_DONE ;
/* scale up: adjust divider now - before frequency change */
2014-04-11 17:39:29 +04:00
writel_relaxed ( ttccs - > scale_clk_ctrl_reg_new ,
ttccs - > ttc . base_addr + TTC_CLK_CNTRL_OFFSET ) ;
2014-02-20 03:14:42 +04:00
break ;
}
case POST_RATE_CHANGE :
/* scale up: pre-change notification did the adjustment */
if ( ndata - > new_rate > ndata - > old_rate )
return NOTIFY_OK ;
/* scale down: adjust divider now - after frequency change */
2014-04-11 17:39:29 +04:00
writel_relaxed ( ttccs - > scale_clk_ctrl_reg_new ,
ttccs - > ttc . base_addr + TTC_CLK_CNTRL_OFFSET ) ;
2014-02-20 03:14:42 +04:00
break ;
2013-03-20 13:15:28 +04:00
case ABORT_RATE_CHANGE :
2014-02-20 03:14:42 +04:00
/* we have to undo the adjustment in case we scale up */
if ( ndata - > new_rate < ndata - > old_rate )
return NOTIFY_OK ;
/* restore original register value */
2014-04-11 17:39:29 +04:00
writel_relaxed ( ttccs - > scale_clk_ctrl_reg_old ,
ttccs - > ttc . base_addr + TTC_CLK_CNTRL_OFFSET ) ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2013-03-20 13:15:28 +04:00
default :
return NOTIFY_DONE ;
}
2014-02-20 03:14:42 +04:00
return NOTIFY_DONE ;
2013-03-20 13:15:28 +04:00
}
2016-05-31 20:52:09 +03:00
static int __init ttc_setup_clocksource ( struct clk * clk , void __iomem * base ,
2014-09-29 03:50:05 +04:00
u32 timer_width )
2012-10-31 23:56:14 +04:00
{
2013-03-27 15:05:28 +04:00
struct ttc_timer_clocksource * ttccs ;
2012-10-31 23:56:14 +04:00
int err ;
ttccs = kzalloc ( sizeof ( * ttccs ) , GFP_KERNEL ) ;
2016-05-31 20:52:09 +03:00
if ( ! ttccs )
return - ENOMEM ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
ttccs - > ttc . clk = clk ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
err = clk_prepare_enable ( ttccs - > ttc . clk ) ;
2016-05-31 20:52:09 +03:00
if ( err ) {
2013-03-20 13:24:59 +04:00
kfree ( ttccs ) ;
2016-05-31 20:52:09 +03:00
return err ;
2013-03-20 13:24:59 +04:00
}
2012-10-31 23:56:14 +04:00
2013-11-27 05:04:50 +04:00
ttccs - > ttc . freq = clk_get_rate ( ttccs - > ttc . clk ) ;
2013-03-27 15:05:28 +04:00
ttccs - > ttc . clk_rate_change_nb . notifier_call =
ttc_rate_change_clocksource_cb ;
ttccs - > ttc . clk_rate_change_nb . next = NULL ;
2016-05-31 20:52:09 +03:00
err = clk_notifier_register ( ttccs - > ttc . clk ,
& ttccs - > ttc . clk_rate_change_nb ) ;
if ( err )
2013-03-20 13:15:28 +04:00
pr_warn ( " Unable to register clock notifier. \n " ) ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
ttccs - > ttc . base_addr = base ;
ttccs - > cs . name = " ttc_clocksource " ;
2012-10-31 23:56:14 +04:00
ttccs - > cs . rating = 200 ;
2013-03-27 15:05:28 +04:00
ttccs - > cs . read = __ttc_clocksource_read ;
2014-09-29 03:50:05 +04:00
ttccs - > cs . mask = CLOCKSOURCE_MASK ( timer_width ) ;
2012-10-31 23:56:14 +04:00
ttccs - > cs . flags = CLOCK_SOURCE_IS_CONTINUOUS ;
2013-03-20 13:15:28 +04:00
/*
* Setup the clock source counter to be an incrementing counter
* with no interrupt and it rolls over at 0xFFFF . Pre - scale
* it by 32 also . Let it start running now .
*/
2014-04-11 17:39:29 +04:00
writel_relaxed ( 0x0 , ttccs - > ttc . base_addr + TTC_IER_OFFSET ) ;
writel_relaxed ( CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN ,
2013-03-27 15:05:28 +04:00
ttccs - > ttc . base_addr + TTC_CLK_CNTRL_OFFSET ) ;
2014-04-11 17:39:29 +04:00
writel_relaxed ( CNT_CNTRL_RESET ,
2013-03-27 15:05:28 +04:00
ttccs - > ttc . base_addr + TTC_CNT_CNTRL_OFFSET ) ;
2012-10-31 23:56:14 +04:00
2013-11-27 05:04:50 +04:00
err = clocksource_register_hz ( & ttccs - > cs , ttccs - > ttc . freq / PRESCALE ) ;
2016-05-31 20:52:09 +03:00
if ( err ) {
2013-03-20 13:24:59 +04:00
kfree ( ttccs ) ;
2016-05-31 20:52:09 +03:00
return err ;
2013-03-20 13:24:59 +04:00
}
2013-07-08 20:51:38 +04:00
ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET ;
2014-09-29 03:50:05 +04:00
sched_clock_register ( ttc_sched_clock_read , timer_width ,
ttccs - > ttc . freq / PRESCALE ) ;
2016-05-31 20:52:09 +03:00
return 0 ;
2012-10-31 23:56:14 +04:00
}
2013-03-27 15:05:28 +04:00
static int ttc_rate_change_clockevent_cb ( struct notifier_block * nb ,
2013-03-20 13:15:28 +04:00
unsigned long event , void * data )
{
struct clk_notifier_data * ndata = data ;
2013-03-27 15:05:28 +04:00
struct ttc_timer * ttc = to_ttc_timer ( nb ) ;
struct ttc_timer_clockevent * ttcce = container_of ( ttc ,
struct ttc_timer_clockevent , ttc ) ;
2013-03-20 13:15:28 +04:00
switch ( event ) {
case POST_RATE_CHANGE :
2013-11-27 05:04:50 +04:00
/* update cached frequency */
ttc - > freq = ndata - > new_rate ;
2014-02-20 03:14:41 +04:00
clockevents_update_freq ( & ttcce - > ce , ndata - > new_rate / PRESCALE ) ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2013-03-20 13:15:28 +04:00
case PRE_RATE_CHANGE :
case ABORT_RATE_CHANGE :
default :
return NOTIFY_DONE ;
}
}
2016-05-31 20:52:09 +03:00
static int __init ttc_setup_clockevent ( struct clk * clk ,
void __iomem * base , u32 irq )
2012-10-31 23:56:14 +04:00
{
2013-03-27 15:05:28 +04:00
struct ttc_timer_clockevent * ttcce ;
2013-03-20 13:15:28 +04:00
int err ;
2012-10-31 23:56:14 +04:00
ttcce = kzalloc ( sizeof ( * ttcce ) , GFP_KERNEL ) ;
2016-05-31 20:52:09 +03:00
if ( ! ttcce )
return - ENOMEM ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
ttcce - > ttc . clk = clk ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
err = clk_prepare_enable ( ttcce - > ttc . clk ) ;
2020-11-16 16:51:23 +03:00
if ( err )
goto out_kfree ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
ttcce - > ttc . clk_rate_change_nb . notifier_call =
ttc_rate_change_clockevent_cb ;
ttcce - > ttc . clk_rate_change_nb . next = NULL ;
2016-05-31 20:52:09 +03:00
err = clk_notifier_register ( ttcce - > ttc . clk ,
& ttcce - > ttc . clk_rate_change_nb ) ;
if ( err ) {
2013-03-20 13:15:28 +04:00
pr_warn ( " Unable to register clock notifier. \n " ) ;
2020-11-16 16:51:23 +03:00
goto out_kfree ;
2016-05-31 20:52:09 +03:00
}
2013-11-27 05:04:50 +04:00
ttcce - > ttc . freq = clk_get_rate ( ttcce - > ttc . clk ) ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
ttcce - > ttc . base_addr = base ;
ttcce - > ce . name = " ttc_clockevent " ;
2012-10-31 23:56:14 +04:00
ttcce - > ce . features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ;
2013-03-27 15:05:28 +04:00
ttcce - > ce . set_next_event = ttc_set_next_event ;
2015-06-18 13:54:16 +03:00
ttcce - > ce . set_state_shutdown = ttc_shutdown ;
ttcce - > ce . set_state_periodic = ttc_set_periodic ;
ttcce - > ce . set_state_oneshot = ttc_shutdown ;
ttcce - > ce . tick_resume = ttc_resume ;
2012-10-31 23:56:14 +04:00
ttcce - > ce . rating = 200 ;
ttcce - > ce . irq = irq ;
2012-12-19 22:18:42 +04:00
ttcce - > ce . cpumask = cpu_possible_mask ;
2012-10-31 23:56:14 +04:00
2013-03-20 13:15:28 +04:00
/*
* Setup the clock event timer to be an interval timer which
* is prescaled by 32 using the interval interrupt . Leave it
* disabled for now .
*/
2014-04-11 17:39:29 +04:00
writel_relaxed ( 0x23 , ttcce - > ttc . base_addr + TTC_CNT_CNTRL_OFFSET ) ;
writel_relaxed ( CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN ,
2013-03-27 15:05:28 +04:00
ttcce - > ttc . base_addr + TTC_CLK_CNTRL_OFFSET ) ;
2014-04-11 17:39:29 +04:00
writel_relaxed ( 0x1 , ttcce - > ttc . base_addr + TTC_IER_OFFSET ) ;
2012-10-31 23:56:14 +04:00
2013-03-27 15:05:28 +04:00
err = request_irq ( irq , ttc_clock_event_interrupt ,
2013-12-09 13:12:10 +04:00
IRQF_TIMER , ttcce - > ce . name , ttcce ) ;
2020-11-16 16:51:23 +03:00
if ( err )
goto out_kfree ;
2012-10-31 23:56:14 +04:00
clockevents_config_and_register ( & ttcce - > ce ,
2013-11-27 05:04:50 +04:00
ttcce - > ttc . freq / PRESCALE , 1 , 0xfffe ) ;
2016-05-31 20:52:09 +03:00
return 0 ;
2020-11-16 16:51:23 +03:00
out_kfree :
kfree ( ttcce ) ;
return err ;
2012-10-31 23:56:14 +04:00
}
2019-11-07 13:36:28 +03:00
static int __init ttc_timer_probe ( struct platform_device * pdev )
2013-03-20 13:15:28 +04:00
{
unsigned int irq ;
void __iomem * timer_baseaddr ;
2013-05-13 21:46:38 +04:00
struct clk * clk_cs , * clk_ce ;
2013-03-20 13:24:59 +04:00
static int initialized ;
2016-05-31 20:52:09 +03:00
int clksel , ret ;
2014-09-29 03:50:05 +04:00
u32 timer_width = 16 ;
2019-11-07 13:36:28 +03:00
struct device_node * timer = pdev - > dev . of_node ;
2013-03-20 13:24:59 +04:00
if ( initialized )
2016-05-31 20:52:09 +03:00
return 0 ;
2013-03-20 13:24:59 +04:00
initialized = 1 ;
2013-03-20 13:15:28 +04:00
/*
* Get the 1 st Triple Timer Counter ( TTC ) block from the device tree
* and use it . Note that the event timer uses the interrupt and it ' s the
* 2 nd TTC hence the irq_of_parse_and_map ( , 1 )
*/
2023-04-25 09:56:11 +03:00
timer_baseaddr = devm_of_iomap ( & pdev - > dev , timer , 0 , NULL ) ;
if ( IS_ERR ( timer_baseaddr ) ) {
2013-03-20 13:15:28 +04:00
pr_err ( " ERROR: invalid timer base address \n " ) ;
2023-04-25 09:56:11 +03:00
return PTR_ERR ( timer_baseaddr ) ;
2013-03-20 13:15:28 +04:00
}
irq = irq_of_parse_and_map ( timer , 1 ) ;
if ( irq < = 0 ) {
pr_err ( " ERROR: invalid interrupt number \n " ) ;
2016-05-31 20:52:09 +03:00
return - EINVAL ;
2013-03-20 13:15:28 +04:00
}
2014-09-29 03:50:05 +04:00
of_property_read_u32 ( timer , " timer-width " , & timer_width ) ;
2014-04-11 17:39:29 +04:00
clksel = readl_relaxed ( timer_baseaddr + TTC_CLK_CNTRL_OFFSET ) ;
2013-05-13 21:46:38 +04:00
clksel = ! ! ( clksel & TTC_CLK_CNTRL_CSRC_MASK ) ;
clk_cs = of_clk_get ( timer , clksel ) ;
if ( IS_ERR ( clk_cs ) ) {
pr_err ( " ERROR: timer input clock not found \n " ) ;
2016-05-31 20:52:09 +03:00
return PTR_ERR ( clk_cs ) ;
2013-05-13 21:46:38 +04:00
}
2014-04-11 17:39:29 +04:00
clksel = readl_relaxed ( timer_baseaddr + 4 + TTC_CLK_CNTRL_OFFSET ) ;
2013-05-13 21:46:38 +04:00
clksel = ! ! ( clksel & TTC_CLK_CNTRL_CSRC_MASK ) ;
clk_ce = of_clk_get ( timer , clksel ) ;
if ( IS_ERR ( clk_ce ) ) {
2013-03-20 13:15:28 +04:00
pr_err ( " ERROR: timer input clock not found \n " ) ;
2023-04-25 09:56:11 +03:00
ret = PTR_ERR ( clk_ce ) ;
goto put_clk_cs ;
2013-03-20 13:15:28 +04:00
}
2016-05-31 20:52:09 +03:00
ret = ttc_setup_clocksource ( clk_cs , timer_baseaddr , timer_width ) ;
if ( ret )
2023-04-25 09:56:11 +03:00
goto put_clk_ce ;
2016-05-31 20:52:09 +03:00
ret = ttc_setup_clockevent ( clk_ce , timer_baseaddr + 4 , irq ) ;
if ( ret )
2023-04-25 09:56:11 +03:00
goto put_clk_ce ;
2013-03-20 13:15:28 +04:00
2018-08-28 04:52:14 +03:00
pr_info ( " %pOFn #0 at %p, irq=%d \n " , timer , timer_baseaddr , irq ) ;
2016-05-31 20:52:09 +03:00
return 0 ;
2023-04-25 09:56:11 +03:00
put_clk_ce :
clk_put ( clk_ce ) ;
put_clk_cs :
clk_put ( clk_cs ) ;
return ret ;
2013-03-20 13:15:28 +04:00
}
2019-11-07 13:36:28 +03:00
static const struct of_device_id ttc_timer_of_match [ ] = {
{ . compatible = " cdns,ttc " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ttc_timer_of_match ) ;
static struct platform_driver ttc_timer_driver = {
. driver = {
. name = " cdns_ttc_timer " ,
. of_match_table = ttc_timer_of_match ,
} ,
} ;
builtin_platform_driver_probe ( ttc_timer_driver , ttc_timer_probe ) ;