2021-12-17 22:57:22 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* MStar timer driver
*
* Copyright ( C ) 2021 Daniel Palmer
* Copyright ( C ) 2021 Romain Perier
*
*/
# include <linux/clk.h>
# include <linux/clockchips.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/irqreturn.h>
# include <linux/sched_clock.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# ifdef CONFIG_ARM
# include <linux/delay.h>
# endif
# include "timer-of.h"
# define TIMER_NAME "msc313e_timer"
# define MSC313E_REG_CTRL 0x00
# define MSC313E_REG_CTRL_TIMER_EN BIT(0)
# define MSC313E_REG_CTRL_TIMER_TRIG BIT(1)
# define MSC313E_REG_CTRL_TIMER_INT_EN BIT(8)
# define MSC313E_REG_TIMER_MAX_LOW 0x08
# define MSC313E_REG_TIMER_MAX_HIGH 0x0c
# define MSC313E_REG_COUNTER_LOW 0x10
# define MSC313E_REG_COUNTER_HIGH 0x14
2021-12-17 22:57:23 +03:00
# define MSC313E_REG_TIMER_DIVIDE 0x18
2021-12-17 22:57:22 +03:00
2021-12-17 22:57:23 +03:00
# define MSC313E_CLK_DIVIDER 9
2021-12-17 22:57:22 +03:00
# define TIMER_SYNC_TICKS 3
# ifdef CONFIG_ARM
struct msc313e_delay {
void __iomem * base ;
struct delay_timer delay ;
} ;
static struct msc313e_delay msc313e_delay ;
# endif
static void __iomem * msc313e_clksrc ;
static void msc313e_timer_stop ( void __iomem * base )
{
writew ( 0 , base + MSC313E_REG_CTRL ) ;
}
static void msc313e_timer_start ( void __iomem * base , bool periodic )
{
u16 reg ;
reg = readw ( base + MSC313E_REG_CTRL ) ;
if ( periodic )
reg | = MSC313E_REG_CTRL_TIMER_EN ;
else
reg | = MSC313E_REG_CTRL_TIMER_TRIG ;
writew ( reg | MSC313E_REG_CTRL_TIMER_INT_EN , base + MSC313E_REG_CTRL ) ;
}
static void msc313e_timer_setup ( void __iomem * base , unsigned long delay )
{
unsigned long flags ;
local_irq_save ( flags ) ;
writew ( delay > > 16 , base + MSC313E_REG_TIMER_MAX_HIGH ) ;
writew ( delay & 0xffff , base + MSC313E_REG_TIMER_MAX_LOW ) ;
local_irq_restore ( flags ) ;
}
static unsigned long msc313e_timer_current_value ( void __iomem * base )
{
unsigned long flags ;
u16 l , h ;
local_irq_save ( flags ) ;
l = readw ( base + MSC313E_REG_COUNTER_LOW ) ;
h = readw ( base + MSC313E_REG_COUNTER_HIGH ) ;
local_irq_restore ( flags ) ;
return ( ( ( u32 ) h ) < < 16 | l ) ;
}
static int msc313e_timer_clkevt_shutdown ( struct clock_event_device * evt )
{
struct timer_of * timer = to_timer_of ( evt ) ;
msc313e_timer_stop ( timer_of_base ( timer ) ) ;
return 0 ;
}
static int msc313e_timer_clkevt_set_oneshot ( struct clock_event_device * evt )
{
struct timer_of * timer = to_timer_of ( evt ) ;
msc313e_timer_stop ( timer_of_base ( timer ) ) ;
msc313e_timer_start ( timer_of_base ( timer ) , false ) ;
return 0 ;
}
static int msc313e_timer_clkevt_set_periodic ( struct clock_event_device * evt )
{
struct timer_of * timer = to_timer_of ( evt ) ;
msc313e_timer_stop ( timer_of_base ( timer ) ) ;
msc313e_timer_setup ( timer_of_base ( timer ) , timer_of_period ( timer ) ) ;
msc313e_timer_start ( timer_of_base ( timer ) , true ) ;
return 0 ;
}
static int msc313e_timer_clkevt_next_event ( unsigned long evt , struct clock_event_device * clkevt )
{
struct timer_of * timer = to_timer_of ( clkevt ) ;
msc313e_timer_stop ( timer_of_base ( timer ) ) ;
msc313e_timer_setup ( timer_of_base ( timer ) , evt ) ;
msc313e_timer_start ( timer_of_base ( timer ) , false ) ;
return 0 ;
}
static irqreturn_t msc313e_timer_clkevt_irq ( int irq , void * dev_id )
{
struct clock_event_device * evt = dev_id ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
static u64 msc313e_timer_clksrc_read ( struct clocksource * cs )
{
return msc313e_timer_current_value ( msc313e_clksrc ) & cs - > mask ;
}
# ifdef CONFIG_ARM
static unsigned long msc313e_read_delay_timer_read ( void )
{
return msc313e_timer_current_value ( msc313e_delay . base ) ;
}
# endif
static u64 msc313e_timer_sched_clock_read ( void )
{
return msc313e_timer_current_value ( msc313e_clksrc ) ;
}
static struct clock_event_device msc313e_clkevt = {
. name = TIMER_NAME ,
. rating = 300 ,
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
. set_state_shutdown = msc313e_timer_clkevt_shutdown ,
. set_state_periodic = msc313e_timer_clkevt_set_periodic ,
. set_state_oneshot = msc313e_timer_clkevt_set_oneshot ,
. tick_resume = msc313e_timer_clkevt_shutdown ,
. set_next_event = msc313e_timer_clkevt_next_event ,
} ;
static int __init msc313e_clkevt_init ( struct device_node * np )
{
int ret ;
struct timer_of * to ;
to = kzalloc ( sizeof ( * to ) , GFP_KERNEL ) ;
if ( ! to )
return - ENOMEM ;
to - > flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE ;
to - > of_irq . handler = msc313e_timer_clkevt_irq ;
ret = timer_of_init ( np , to ) ;
if ( ret )
return ret ;
2021-12-17 22:57:23 +03:00
if ( of_device_is_compatible ( np , " sstar,ssd20xd-timer " ) ) {
to - > of_clk . rate = clk_get_rate ( to - > of_clk . clk ) / MSC313E_CLK_DIVIDER ;
to - > of_clk . period = DIV_ROUND_UP ( to - > of_clk . rate , HZ ) ;
writew ( MSC313E_CLK_DIVIDER - 1 , timer_of_base ( to ) + MSC313E_REG_TIMER_DIVIDE ) ;
}
2021-12-17 22:57:22 +03:00
msc313e_clkevt . cpumask = cpu_possible_mask ;
msc313e_clkevt . irq = to - > of_irq . irq ;
to - > clkevt = msc313e_clkevt ;
clockevents_config_and_register ( & to - > clkevt , timer_of_rate ( to ) ,
TIMER_SYNC_TICKS , 0xffffffff ) ;
return 0 ;
}
static int __init msc313e_clksrc_init ( struct device_node * np )
{
struct timer_of to = { 0 } ;
int ret ;
u16 reg ;
to . flags = TIMER_OF_BASE | TIMER_OF_CLOCK ;
ret = timer_of_init ( np , & to ) ;
if ( ret )
return ret ;
msc313e_clksrc = timer_of_base ( & to ) ;
reg = readw ( msc313e_clksrc + MSC313E_REG_CTRL ) ;
reg | = MSC313E_REG_CTRL_TIMER_EN ;
writew ( reg , msc313e_clksrc + MSC313E_REG_CTRL ) ;
# ifdef CONFIG_ARM
msc313e_delay . base = timer_of_base ( & to ) ;
msc313e_delay . delay . read_current_timer = msc313e_read_delay_timer_read ;
msc313e_delay . delay . freq = timer_of_rate ( & to ) ;
register_current_timer_delay ( & msc313e_delay . delay ) ;
# endif
sched_clock_register ( msc313e_timer_sched_clock_read , 32 , timer_of_rate ( & to ) ) ;
return clocksource_mmio_init ( timer_of_base ( & to ) , TIMER_NAME , timer_of_rate ( & to ) , 300 , 32 ,
msc313e_timer_clksrc_read ) ;
}
static int __init msc313e_timer_init ( struct device_node * np )
{
int ret = 0 ;
static int num_called ;
switch ( num_called ) {
case 0 :
ret = msc313e_clksrc_init ( np ) ;
if ( ret )
return ret ;
break ;
default :
ret = msc313e_clkevt_init ( np ) ;
if ( ret )
return ret ;
break ;
}
num_called + + ;
return 0 ;
}
TIMER_OF_DECLARE ( msc313 , " mstar,msc313e-timer " , msc313e_timer_init ) ;
2021-12-17 22:57:23 +03:00
TIMER_OF_DECLARE ( ssd20xd , " sstar,ssd20xd-timer " , msc313e_timer_init ) ;