2010-10-08 21:40:19 +04:00
/*
* OMAP 32 ksynctimer / counter_32k - related code
*
* Copyright ( C ) 2009 Texas Instruments
* Copyright ( C ) 2010 Nokia Corporation
* Tony Lindgren < tony @ atomide . com >
* Added OMAP4 support - Santosh Shilimkar < santosh . shilimkar @ ti . com >
*
* 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 .
*
* NOTE : This timer is not the same timer as the old OMAP1 MPU timer .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/clk.h>
2010-11-26 20:06:02 +03:00
# include <linux/err.h>
2010-10-08 21:40:19 +04:00
# include <linux/io.h>
2011-07-11 10:05:34 +04:00
# include <linux/clocksource.h>
2010-10-08 21:40:19 +04:00
2010-12-16 00:53:51 +03:00
# include <asm/sched_clock.h>
2010-10-08 21:40:19 +04:00
2012-02-24 22:34:35 +04:00
# include <plat/hardware.h>
2010-10-08 21:40:19 +04:00
# include <plat/common.h>
# include <plat/board.h>
# include <plat/clock.h>
/*
* 32 KHz clocksource . . . always available , on pretty most chips except
* OMAP 730 and 1510. Other timers could be used as clocksources , with
* higher resolution in free - running counter modes ( e . g . 12 MHz xtal ) ,
* but systems won ' t necessarily want to spend resources that way .
*/
2011-07-11 10:05:34 +04:00
static void __iomem * timer_32k_base ;
2010-10-08 21:40:19 +04:00
# define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
2011-12-15 15:19:23 +04:00
static u32 notrace omap_32k_read_sched_clock ( void )
2010-10-08 21:40:19 +04:00
{
2011-12-15 15:19:23 +04:00
return timer_32k_base ? __raw_readl ( timer_32k_base ) : 0 ;
2010-10-08 21:40:19 +04:00
}
/**
* read_persistent_clock - Return time from a persistent clock .
*
* Reads the time from a source which isn ' t disabled during PM , the
* 32 k sync timer . Convert the cycles elapsed since last read into
* nsecs and adds to a monotonically increasing timespec .
*/
static struct timespec persistent_ts ;
static cycles_t cycles , last_cycles ;
2011-07-11 10:05:34 +04:00
static unsigned int persistent_mult , persistent_shift ;
2010-10-08 21:40:19 +04:00
void read_persistent_clock ( struct timespec * ts )
{
unsigned long long nsecs ;
cycles_t delta ;
struct timespec * tsp = & persistent_ts ;
last_cycles = cycles ;
2011-07-11 10:05:34 +04:00
cycles = timer_32k_base ? __raw_readl ( timer_32k_base ) : 0 ;
2010-10-08 21:40:19 +04:00
delta = cycles - last_cycles ;
2011-07-11 10:05:34 +04:00
nsecs = clocksource_cyc2ns ( delta , persistent_mult , persistent_shift ) ;
2010-10-08 21:40:19 +04:00
timespec_add_ns ( tsp , nsecs ) ;
* ts = * tsp ;
}
2011-01-16 07:32:01 +03:00
int __init omap_init_clocksource_32k ( void )
2010-10-08 21:40:19 +04:00
{
static char err [ ] __initdata = KERN_ERR
" %s: can't register clocksource! \n " ;
if ( cpu_is_omap16xx ( ) | | cpu_class_is_omap2 ( ) ) {
2011-07-11 10:05:34 +04:00
u32 pbase ;
unsigned long size = SZ_4K ;
void __iomem * base ;
2010-10-08 21:40:19 +04:00
struct clk * sync_32k_ick ;
2011-07-11 10:05:34 +04:00
if ( cpu_is_omap16xx ( ) ) {
pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED ;
size = SZ_1K ;
} else if ( cpu_is_omap2420 ( ) )
pbase = OMAP2420_32KSYNCT_BASE + 0x10 ;
2010-10-08 21:40:19 +04:00
else if ( cpu_is_omap2430 ( ) )
2011-07-11 10:05:34 +04:00
pbase = OMAP2430_32KSYNCT_BASE + 0x10 ;
2010-10-08 21:40:19 +04:00
else if ( cpu_is_omap34xx ( ) )
2011-07-11 10:05:34 +04:00
pbase = OMAP3430_32KSYNCT_BASE + 0x10 ;
2010-10-08 21:40:19 +04:00
else if ( cpu_is_omap44xx ( ) )
2011-07-11 10:05:34 +04:00
pbase = OMAP4430_32KSYNCT_BASE + 0x10 ;
2010-10-08 21:40:19 +04:00
else
return - ENODEV ;
2011-07-11 10:05:34 +04:00
/* For this to work we must have a static mapping in io.c for this area */
base = ioremap ( pbase , size ) ;
if ( ! base )
return - ENODEV ;
2010-10-08 21:40:19 +04:00
sync_32k_ick = clk_get ( NULL , " omap_32ksync_ick " ) ;
2010-11-26 20:06:02 +03:00
if ( ! IS_ERR ( sync_32k_ick ) )
2010-10-08 21:40:19 +04:00
clk_enable ( sync_32k_ick ) ;
2011-07-11 10:05:34 +04:00
timer_32k_base = base ;
/*
* 120000 rough estimate from the calculations in
* __clocksource_updatefreq_scale .
*/
clocks_calc_mult_shift ( & persistent_mult , & persistent_shift ,
32768 , NSEC_PER_SEC , 120000 ) ;
2010-10-08 21:40:19 +04:00
2011-07-11 10:05:34 +04:00
if ( clocksource_mmio_init ( base , " 32k_counter " , 32768 , 250 , 32 ,
clocksource_mmio_readl_up ) )
printk ( err , " 32k_counter " ) ;
2010-12-16 00:53:51 +03:00
2011-12-15 15:19:23 +04:00
setup_sched_clock ( omap_32k_read_sched_clock , 32 , 32768 ) ;
2010-10-08 21:40:19 +04:00
}
return 0 ;
}