2015-01-27 20:52:42 +03:00
/*
* linux / arch / h8300 / kernel / cpu / timer / timer8 . c
*
* Yoshinori Sato < ysato @ users . sourcefoge . jp >
*
* 8 bit Timer driver
*
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/clockchips.h>
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/of.h>
2015-11-06 19:31:44 +03:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2015-01-27 20:52:42 +03:00
# define _8TCR 0
# define _8TCSR 2
# define TCORA 4
# define TCORB 6
# define _8TCNT 8
2015-12-04 20:48:18 +03:00
# define CMIEA 6
# define CMFA 6
2015-01-27 20:52:42 +03:00
# define FLAG_STARTED (1 << 3)
2015-11-06 19:31:44 +03:00
# define SCALE 64
2015-12-04 20:48:18 +03:00
# define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
# define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
2015-01-27 20:52:42 +03:00
struct timer8_priv {
struct clock_event_device ced ;
2015-11-09 00:55:12 +03:00
void __iomem * mapbase ;
2015-01-27 20:52:42 +03:00
unsigned long flags ;
unsigned int rate ;
} ;
static irqreturn_t timer8_interrupt ( int irq , void * dev_id )
{
struct timer8_priv * p = dev_id ;
2015-11-08 20:07:38 +03:00
if ( clockevent_state_oneshot ( & p - > ced ) )
2015-12-04 20:48:18 +03:00
iowrite16be ( 0x0000 , p - > mapbase + _8TCR ) ;
2015-11-08 20:07:38 +03:00
p - > ced . event_handler ( & p - > ced ) ;
2015-01-27 20:52:42 +03:00
2015-12-04 20:48:18 +03:00
bclr ( CMFA , p - > mapbase + _8TCSR ) ;
2015-12-04 20:48:16 +03:00
2015-01-27 20:52:42 +03:00
return IRQ_HANDLED ;
}
static void timer8_set_next ( struct timer8_priv * p , unsigned long delta )
{
if ( delta > = 0x10000 )
2015-11-09 11:02:38 +03:00
pr_warn ( " delta out of range \n " ) ;
2015-12-04 20:48:18 +03:00
bclr ( CMIEA , p - > mapbase + _8TCR ) ;
iowrite16be ( delta , p - > mapbase + TCORA ) ;
iowrite16be ( 0x0000 , p - > mapbase + _8TCNT ) ;
bclr ( CMFA , p - > mapbase + _8TCSR ) ;
bset ( CMIEA , p - > mapbase + _8TCR ) ;
2015-01-27 20:52:42 +03:00
}
static int timer8_enable ( struct timer8_priv * p )
{
2015-12-04 20:48:18 +03:00
iowrite16be ( 0xffff , p - > mapbase + TCORA ) ;
iowrite16be ( 0x0000 , p - > mapbase + _8TCNT ) ;
iowrite16be ( 0x0c02 , p - > mapbase + _8TCR ) ;
2015-01-27 20:52:42 +03:00
return 0 ;
}
static int timer8_start ( struct timer8_priv * p )
{
2015-11-09 01:24:28 +03:00
int ret ;
2015-01-27 20:52:42 +03:00
2015-11-09 01:24:28 +03:00
if ( ( p - > flags & FLAG_STARTED ) )
return 0 ;
2015-01-27 20:52:42 +03:00
2015-11-09 01:24:28 +03:00
ret = timer8_enable ( p ) ;
if ( ! ret )
p - > flags | = FLAG_STARTED ;
2015-01-27 20:52:42 +03:00
return ret ;
}
static void timer8_stop ( struct timer8_priv * p )
{
2015-12-04 20:48:18 +03:00
iowrite16be ( 0x0000 , p - > mapbase + _8TCR ) ;
2015-01-27 20:52:42 +03:00
}
static inline struct timer8_priv * ced_to_priv ( struct clock_event_device * ced )
{
return container_of ( ced , struct timer8_priv , ced ) ;
}
2015-11-08 19:46:54 +03:00
static void timer8_clock_event_start ( struct timer8_priv * p , unsigned long delta )
2015-01-27 20:52:42 +03:00
{
timer8_start ( p ) ;
2015-11-08 19:46:54 +03:00
timer8_set_next ( p , delta ) ;
2015-01-27 20:52:42 +03:00
}
2015-07-27 12:32:00 +03:00
static int timer8_clock_event_shutdown ( struct clock_event_device * ced )
{
timer8_stop ( ced_to_priv ( ced ) ) ;
return 0 ;
}
static int timer8_clock_event_periodic ( struct clock_event_device * ced )
2015-01-27 20:52:42 +03:00
{
struct timer8_priv * p = ced_to_priv ( ced ) ;
2015-11-06 19:31:44 +03:00
pr_info ( " %s: used for periodic clock events \n " , ced - > name ) ;
2015-07-27 12:32:00 +03:00
timer8_stop ( p ) ;
2015-11-08 19:46:54 +03:00
timer8_clock_event_start ( p , ( p - > rate + HZ / 2 ) / HZ ) ;
2015-07-27 12:32:00 +03:00
return 0 ;
}
static int timer8_clock_event_oneshot ( struct clock_event_device * ced )
{
struct timer8_priv * p = ced_to_priv ( ced ) ;
2015-11-06 19:31:44 +03:00
pr_info ( " %s: used for oneshot clock events \n " , ced - > name ) ;
2015-07-27 12:32:00 +03:00
timer8_stop ( p ) ;
2015-11-08 19:46:54 +03:00
timer8_clock_event_start ( p , 0x10000 ) ;
2015-07-27 12:32:00 +03:00
return 0 ;
2015-01-27 20:52:42 +03:00
}
static int timer8_clock_event_next ( unsigned long delta ,
struct clock_event_device * ced )
{
struct timer8_priv * p = ced_to_priv ( ced ) ;
2015-07-27 12:32:00 +03:00
BUG_ON ( ! clockevent_state_oneshot ( ced ) ) ;
2015-01-27 20:52:42 +03:00
timer8_set_next ( p , delta - 1 ) ;
return 0 ;
}
2015-11-06 19:31:44 +03:00
static struct timer8_priv timer8_priv = {
. ced = {
. name = " h8300_8timer " ,
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
. rating = 200 ,
. set_next_event = timer8_clock_event_next ,
. set_state_shutdown = timer8_clock_event_shutdown ,
. set_state_periodic = timer8_clock_event_periodic ,
. set_state_oneshot = timer8_clock_event_oneshot ,
} ,
} ;
2016-06-06 18:56:37 +03:00
static int __init h8300_8timer_init ( struct device_node * node )
2015-01-27 20:52:42 +03:00
{
2015-11-06 19:31:44 +03:00
void __iomem * base ;
2016-06-06 18:56:37 +03:00
int irq , ret ;
2015-11-06 19:31:44 +03:00
struct clk * clk ;
2015-01-27 20:52:42 +03:00
2015-11-06 19:31:44 +03:00
clk = of_clk_get ( node , 0 ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " failed to get clock for clockevent \n " ) ;
2016-06-06 18:56:37 +03:00
return PTR_ERR ( clk ) ;
2015-11-06 19:31:44 +03:00
}
2015-01-27 20:52:42 +03:00
2016-06-06 18:56:37 +03:00
ret = ENXIO ;
2015-11-06 19:31:44 +03:00
base = of_iomap ( node , 0 ) ;
if ( ! base ) {
pr_err ( " failed to map registers for clockevent \n " ) ;
goto free_clk ;
2015-01-27 20:52:42 +03:00
}
2016-06-06 18:56:37 +03:00
ret = - EINVAL ;
2015-11-06 19:31:44 +03:00
irq = irq_of_parse_and_map ( node , 0 ) ;
2015-11-08 19:56:18 +03:00
if ( ! irq ) {
2015-11-06 19:31:44 +03:00
pr_err ( " failed to get irq for clockevent \n " ) ;
goto unmap_reg ;
2015-01-27 20:52:42 +03:00
}
2015-11-09 00:55:12 +03:00
timer8_priv . mapbase = base ;
2015-11-09 01:24:28 +03:00
2015-12-04 20:48:17 +03:00
timer8_priv . rate = clk_get_rate ( clk ) / SCALE ;
if ( ! timer8_priv . rate ) {
2015-11-09 01:24:28 +03:00
pr_err ( " Failed to get rate for the clocksource \n " ) ;
goto unmap_reg ;
}
2015-01-27 20:52:42 +03:00
2015-12-04 20:48:17 +03:00
if ( request_irq ( irq , timer8_interrupt , IRQF_TIMER ,
timer8_priv . ced . name , & timer8_priv ) < 0 ) {
2015-11-06 19:31:44 +03:00
pr_err ( " failed to request irq %d for clockevent \n " , irq ) ;
goto unmap_reg ;
2015-01-27 20:52:42 +03:00
}
2015-11-09 01:24:28 +03:00
2015-12-04 20:48:17 +03:00
clockevents_config_and_register ( & timer8_priv . ced ,
timer8_priv . rate , 1 , 0x0000ffff ) ;
2015-11-06 19:31:44 +03:00
2016-06-06 18:56:37 +03:00
return 0 ;
2015-11-06 19:31:44 +03:00
unmap_reg :
iounmap ( base ) ;
free_clk :
clk_put ( clk ) ;
2016-06-06 18:56:37 +03:00
return ret ;
2015-01-27 20:52:42 +03:00
}
2016-06-07 01:27:44 +03:00
CLOCKSOURCE_OF_DECLARE ( h8300_8bit , " renesas,8bit-timer " , h8300_8timer_init ) ;