2011-07-25 20:36:42 +04:00
/*
2012-07-12 00:13:16 +04:00
* Copyright ( C ) 2012 Altera Corporation
2011-07-25 20:36:42 +04:00
* Copyright ( c ) 2011 Picochip Ltd . , Jamie Iles
*
2012-07-12 00:13:16 +04:00
* Modified from mach - picoxcell / time . c
*
2011-07-25 20:36:42 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
2012-07-12 00:13:16 +04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2011-07-25 20:36:42 +04:00
*/
# include <linux/dw_apb_timer.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <asm/mach/time.h>
# include <asm/sched_clock.h>
static void timer_get_base_and_rate ( struct device_node * np ,
void __iomem * * base , u32 * rate )
{
* base = of_iomap ( np , 0 ) ;
if ( ! * base )
panic ( " Unable to map regs for %s " , np - > name ) ;
2012-07-12 00:13:16 +04:00
if ( of_property_read_u32 ( np , " clock-freq " , rate ) & &
of_property_read_u32 ( np , " clock-frequency " , rate ) )
panic ( " No clock-frequency property for %s " , np - > name ) ;
2011-07-25 20:36:42 +04:00
}
2012-07-12 00:13:16 +04:00
static void add_clockevent ( struct device_node * event_timer )
2011-07-25 20:36:42 +04:00
{
void __iomem * iobase ;
struct dw_apb_clock_event_device * ced ;
u32 irq , rate ;
irq = irq_of_parse_and_map ( event_timer , 0 ) ;
if ( irq = = NO_IRQ )
panic ( " No IRQ for clock event timer " ) ;
timer_get_base_and_rate ( event_timer , & iobase , & rate ) ;
ced = dw_apb_clockevent_init ( 0 , event_timer - > name , 300 , iobase , irq ,
rate ) ;
if ( ! ced )
panic ( " Unable to initialise clockevent device " ) ;
dw_apb_clockevent_register ( ced ) ;
}
2012-07-12 00:13:16 +04:00
static void add_clocksource ( struct device_node * source_timer )
2011-07-25 20:36:42 +04:00
{
void __iomem * iobase ;
struct dw_apb_clocksource * cs ;
u32 rate ;
timer_get_base_and_rate ( source_timer , & iobase , & rate ) ;
cs = dw_apb_clocksource_init ( 300 , source_timer - > name , iobase , rate ) ;
if ( ! cs )
panic ( " Unable to initialise clocksource device " ) ;
dw_apb_clocksource_start ( cs ) ;
dw_apb_clocksource_register ( cs ) ;
}
static void __iomem * sched_io_base ;
2012-07-12 00:13:16 +04:00
static u32 read_sched_clock ( void )
2011-07-25 20:36:42 +04:00
{
2011-12-15 15:19:23 +04:00
return __raw_readl ( sched_io_base ) ;
2011-07-25 20:36:42 +04:00
}
2012-07-12 00:13:16 +04:00
static const struct of_device_id sptimer_ids [ ] __initconst = {
2011-07-25 20:36:42 +04:00
{ . compatible = " picochip,pc3x2-rtc " } ,
2012-07-12 00:13:16 +04:00
{ . compatible = " snps,dw-apb-timer-sp " } ,
2011-07-25 20:36:42 +04:00
{ /* Sentinel */ } ,
} ;
2012-07-12 00:13:16 +04:00
static void init_sched_clock ( void )
2011-07-25 20:36:42 +04:00
{
struct device_node * sched_timer ;
u32 rate ;
2012-07-12 00:13:16 +04:00
sched_timer = of_find_matching_node ( NULL , sptimer_ids ) ;
2011-07-25 20:36:42 +04:00
if ( ! sched_timer )
panic ( " No RTC for sched clock to use " ) ;
timer_get_base_and_rate ( sched_timer , & sched_io_base , & rate ) ;
of_node_put ( sched_timer ) ;
2012-07-12 00:13:16 +04:00
setup_sched_clock ( read_sched_clock , 32 , rate ) ;
2011-07-25 20:36:42 +04:00
}
2012-07-12 00:13:16 +04:00
static const struct of_device_id osctimer_ids [ ] __initconst = {
2011-07-25 20:36:42 +04:00
{ . compatible = " picochip,pc3x2-timer " } ,
2012-07-12 00:13:16 +04:00
{ . compatible = " snps,dw-apb-timer-osc " } ,
2011-07-25 20:36:42 +04:00
{ } ,
} ;
2012-11-08 23:40:59 +04:00
void __init dw_apb_timer_init ( void )
2011-07-25 20:36:42 +04:00
{
struct device_node * event_timer , * source_timer ;
2012-07-12 00:13:16 +04:00
event_timer = of_find_matching_node ( NULL , osctimer_ids ) ;
2011-07-25 20:36:42 +04:00
if ( ! event_timer )
panic ( " No timer for clockevent " ) ;
2012-07-12 00:13:16 +04:00
add_clockevent ( event_timer ) ;
2011-07-25 20:36:42 +04:00
2012-07-12 00:13:16 +04:00
source_timer = of_find_matching_node ( event_timer , osctimer_ids ) ;
2011-07-25 20:36:42 +04:00
if ( ! source_timer )
panic ( " No timer for clocksource " ) ;
2012-07-12 00:13:16 +04:00
add_clocksource ( source_timer ) ;
2011-07-25 20:36:42 +04:00
of_node_put ( source_timer ) ;
2012-07-12 00:13:16 +04:00
init_sched_clock ( ) ;
2011-07-25 20:36:42 +04:00
}