2005-09-07 17:20:26 +01:00
/*
* linux / arch / arm / plat - omap / dmtimer . c
*
* OMAP Dual - Mode Timers
*
* Copyright ( C ) 2005 Nokia Corporation
2006-06-26 16:16:12 -07:00
* OMAP2 support by Juha Yrjola
* API improvements and OMAP2 clock framework support by Timo Teras
2005-09-07 17:20:26 +01:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/init.h>
2006-06-26 16:16:12 -07:00
# include <linux/spinlock.h>
# include <linux/errno.h>
# include <linux/list.h>
# include <linux/clk.h>
# include <linux/delay.h>
2005-11-16 14:51:20 +00:00
# include <asm/hardware.h>
2005-09-07 17:20:26 +01:00
# include <asm/arch/dmtimer.h>
# include <asm/io.h>
# include <asm/arch/irqs.h>
2006-06-26 16:16:12 -07:00
/* register offsets */
2005-09-07 17:20:26 +01:00
# define OMAP_TIMER_ID_REG 0x00
# define OMAP_TIMER_OCP_CFG_REG 0x10
# define OMAP_TIMER_SYS_STAT_REG 0x14
# define OMAP_TIMER_STAT_REG 0x18
# define OMAP_TIMER_INT_EN_REG 0x1c
# define OMAP_TIMER_WAKEUP_EN_REG 0x20
# define OMAP_TIMER_CTRL_REG 0x24
# define OMAP_TIMER_COUNTER_REG 0x28
# define OMAP_TIMER_LOAD_REG 0x2c
# define OMAP_TIMER_TRIGGER_REG 0x30
# define OMAP_TIMER_WRITE_PEND_REG 0x34
# define OMAP_TIMER_MATCH_REG 0x38
# define OMAP_TIMER_CAPTURE_REG 0x3c
# define OMAP_TIMER_IF_CTRL_REG 0x40
2006-06-26 16:16:12 -07:00
/* timer control reg bits */
# define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
# define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
# define OMAP_TIMER_CTRL_PT (1 << 12)
# define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
# define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
# define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
# define OMAP_TIMER_CTRL_SCPWM (1 << 7)
# define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
# define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
# define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */
# define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
# define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
struct omap_dm_timer {
unsigned long phys_base ;
int irq ;
# ifdef CONFIG_ARCH_OMAP2
struct clk * iclk , * fclk ;
# endif
void __iomem * io_base ;
unsigned reserved : 1 ;
2006-09-25 12:41:42 +03:00
unsigned enabled : 1 ;
2006-06-26 16:16:12 -07:00
} ;
# ifdef CONFIG_ARCH_OMAP1
2006-09-25 12:41:35 +03:00
# define omap_dm_clk_enable(x)
# define omap_dm_clk_disable(x)
2006-06-26 16:16:12 -07:00
static struct omap_dm_timer dm_timers [ ] = {
{ . phys_base = 0xfffb1400 , . irq = INT_1610_GPTIMER1 } ,
{ . phys_base = 0xfffb1c00 , . irq = INT_1610_GPTIMER2 } ,
{ . phys_base = 0xfffb2400 , . irq = INT_1610_GPTIMER3 } ,
{ . phys_base = 0xfffb2c00 , . irq = INT_1610_GPTIMER4 } ,
{ . phys_base = 0xfffb3400 , . irq = INT_1610_GPTIMER5 } ,
{ . phys_base = 0xfffb3c00 , . irq = INT_1610_GPTIMER6 } ,
{ . phys_base = 0xfffb4400 , . irq = INT_1610_GPTIMER7 } ,
{ . phys_base = 0xfffb4c00 , . irq = INT_1610_GPTIMER8 } ,
} ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
# elif defined(CONFIG_ARCH_OMAP2)
2005-09-07 17:20:26 +01:00
2006-09-25 12:41:35 +03:00
# define omap_dm_clk_enable(x) clk_enable(x)
# define omap_dm_clk_disable(x) clk_disable(x)
2005-09-07 17:20:26 +01:00
static struct omap_dm_timer dm_timers [ ] = {
2006-06-26 16:16:12 -07:00
{ . phys_base = 0x48028000 , . irq = INT_24XX_GPTIMER1 } ,
{ . phys_base = 0x4802a000 , . irq = INT_24XX_GPTIMER2 } ,
{ . phys_base = 0x48078000 , . irq = INT_24XX_GPTIMER3 } ,
{ . phys_base = 0x4807a000 , . irq = INT_24XX_GPTIMER4 } ,
{ . phys_base = 0x4807c000 , . irq = INT_24XX_GPTIMER5 } ,
{ . phys_base = 0x4807e000 , . irq = INT_24XX_GPTIMER6 } ,
{ . phys_base = 0x48080000 , . irq = INT_24XX_GPTIMER7 } ,
{ . phys_base = 0x48082000 , . irq = INT_24XX_GPTIMER8 } ,
{ . phys_base = 0x48084000 , . irq = INT_24XX_GPTIMER9 } ,
{ . phys_base = 0x48086000 , . irq = INT_24XX_GPTIMER10 } ,
{ . phys_base = 0x48088000 , . irq = INT_24XX_GPTIMER11 } ,
{ . phys_base = 0x4808a000 , . irq = INT_24XX_GPTIMER12 } ,
2005-09-07 17:20:26 +01:00
} ;
2006-06-26 16:16:23 -07:00
static const char * dm_source_names [ ] = {
" sys_ck " ,
" func_32k_ck " ,
" alt_ck "
} ;
static struct clk * dm_source_clocks [ 3 ] ;
2006-06-26 16:16:12 -07:00
# else
# error OMAP architecture not supported!
# endif
static const int dm_timer_count = ARRAY_SIZE ( dm_timers ) ;
2005-09-07 17:20:26 +01:00
static spinlock_t dm_timer_lock ;
2006-06-26 16:16:12 -07:00
static inline u32 omap_dm_timer_read_reg ( struct omap_dm_timer * timer , int reg )
{
return readl ( timer - > io_base + reg ) ;
}
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
static void omap_dm_timer_write_reg ( struct omap_dm_timer * timer , int reg , u32 value )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
writel ( value , timer - > io_base + reg ) ;
2005-09-07 17:20:26 +01:00
while ( omap_dm_timer_read_reg ( timer , OMAP_TIMER_WRITE_PEND_REG ) )
;
}
2006-06-26 16:16:12 -07:00
static void omap_dm_timer_wait_for_reset ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
int c ;
c = 0 ;
while ( ! ( omap_dm_timer_read_reg ( timer , OMAP_TIMER_SYS_STAT_REG ) & 1 ) ) {
c + + ;
if ( c > 100000 ) {
printk ( KERN_ERR " Timer failed to reset \n " ) ;
return ;
}
}
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
static void omap_dm_timer_reset ( struct omap_dm_timer * timer )
{
u32 l ;
2006-09-25 12:41:44 +03:00
if ( ! cpu_class_is_omap2 ( ) | | timer ! = & dm_timers [ 0 ] ) {
2006-06-26 16:16:13 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_IF_CTRL_REG , 0x06 ) ;
omap_dm_timer_wait_for_reset ( timer ) ;
}
2006-09-25 12:41:42 +03:00
omap_dm_timer_set_source ( timer , OMAP_TIMER_SRC_32_KHZ ) ;
2006-06-26 16:16:12 -07:00
/* Set to smart-idle mode */
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_OCP_CFG_REG ) ;
l | = 0x02 < < 3 ;
2006-09-25 12:41:44 +03:00
if ( cpu_class_is_omap2 ( ) & & timer = = & dm_timers [ 0 ] ) {
/* Enable wake-up only for GPT1 on OMAP2 CPUs*/
l | = 1 < < 2 ;
/* Non-posted mode */
omap_dm_timer_write_reg ( timer , OMAP_TIMER_IF_CTRL_REG , 0 ) ;
}
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_OCP_CFG_REG , l ) ;
}
2006-06-26 16:16:23 -07:00
static void omap_dm_timer_prepare ( struct omap_dm_timer * timer )
2006-06-26 16:16:12 -07:00
{
2006-09-25 12:41:42 +03:00
omap_dm_timer_enable ( timer ) ;
2006-06-26 16:16:12 -07:00
omap_dm_timer_reset ( timer ) ;
}
struct omap_dm_timer * omap_dm_timer_request ( void )
{
struct omap_dm_timer * timer = NULL ;
unsigned long flags ;
int i ;
spin_lock_irqsave ( & dm_timer_lock , flags ) ;
for ( i = 0 ; i < dm_timer_count ; i + + ) {
if ( dm_timers [ i ] . reserved )
continue ;
timer = & dm_timers [ i ] ;
2006-06-26 16:16:23 -07:00
timer - > reserved = 1 ;
2006-06-26 16:16:12 -07:00
break ;
}
spin_unlock_irqrestore ( & dm_timer_lock , flags ) ;
2006-06-26 16:16:23 -07:00
if ( timer ! = NULL )
omap_dm_timer_prepare ( timer ) ;
2006-06-26 16:16:12 -07:00
return timer ;
}
struct omap_dm_timer * omap_dm_timer_request_specific ( int id )
2005-09-07 17:20:26 +01:00
{
struct omap_dm_timer * timer ;
2006-06-26 16:16:12 -07:00
unsigned long flags ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
spin_lock_irqsave ( & dm_timer_lock , flags ) ;
if ( id < = 0 | | id > dm_timer_count | | dm_timers [ id - 1 ] . reserved ) {
spin_unlock_irqrestore ( & dm_timer_lock , flags ) ;
printk ( " BUG: warning at %s:%d/%s(): unable to get timer %d \n " ,
__FILE__ , __LINE__ , __FUNCTION__ , id ) ;
dump_stack ( ) ;
return NULL ;
}
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
timer = & dm_timers [ id - 1 ] ;
2006-06-26 16:16:23 -07:00
timer - > reserved = 1 ;
2006-06-26 16:16:12 -07:00
spin_unlock_irqrestore ( & dm_timer_lock , flags ) ;
2006-06-26 16:16:23 -07:00
omap_dm_timer_prepare ( timer ) ;
2006-06-26 16:16:12 -07:00
return timer ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_free ( struct omap_dm_timer * timer )
{
2006-09-25 12:41:42 +03:00
omap_dm_timer_enable ( timer ) ;
2006-06-26 16:16:12 -07:00
omap_dm_timer_reset ( timer ) ;
2006-09-25 12:41:42 +03:00
omap_dm_timer_disable ( timer ) ;
2006-09-25 12:41:35 +03:00
2006-06-26 16:16:12 -07:00
WARN_ON ( ! timer - > reserved ) ;
timer - > reserved = 0 ;
}
2006-09-25 12:41:42 +03:00
void omap_dm_timer_enable ( struct omap_dm_timer * timer )
{
if ( timer - > enabled )
return ;
omap_dm_clk_enable ( timer - > fclk ) ;
omap_dm_clk_enable ( timer - > iclk ) ;
timer - > enabled = 1 ;
}
void omap_dm_timer_disable ( struct omap_dm_timer * timer )
{
if ( ! timer - > enabled )
return ;
omap_dm_clk_disable ( timer - > iclk ) ;
omap_dm_clk_disable ( timer - > fclk ) ;
timer - > enabled = 0 ;
}
2006-06-26 16:16:12 -07:00
int omap_dm_timer_get_irq ( struct omap_dm_timer * timer )
{
return timer - > irq ;
}
# if defined(CONFIG_ARCH_OMAP1)
struct clk * omap_dm_timer_get_fclk ( struct omap_dm_timer * timer )
{
BUG ( ) ;
}
2005-09-07 17:20:26 +01:00
2006-04-02 17:46:21 +01:00
/**
* omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
* @ inputmask : current value of idlect mask
*/
__u32 omap_dm_timer_modify_idlect_mask ( __u32 inputmask )
{
2006-06-26 16:16:12 -07:00
int i ;
2006-04-02 17:46:21 +01:00
/* If ARMXOR cannot be idled this function call is unnecessary */
if ( ! ( inputmask & ( 1 < < 1 ) ) )
return inputmask ;
/* If any active timer is using ARMXOR return modified mask */
2006-06-26 16:16:12 -07:00
for ( i = 0 ; i < dm_timer_count ; i + + ) {
u32 l ;
2006-07-01 19:56:42 +01:00
l = omap_dm_timer_read_reg ( & dm_timers [ i ] , OMAP_TIMER_CTRL_REG ) ;
2006-06-26 16:16:12 -07:00
if ( l & OMAP_TIMER_CTRL_ST ) {
if ( ( ( omap_readl ( MOD_CONF_CTRL_1 ) > > ( i * 2 ) ) & 0x03 ) = = 0 )
2006-04-02 17:46:21 +01:00
inputmask & = ~ ( 1 < < 1 ) ;
else
inputmask & = ~ ( 1 < < 2 ) ;
}
2006-06-26 16:16:12 -07:00
}
2006-04-02 17:46:21 +01:00
return inputmask ;
}
2006-06-26 16:16:12 -07:00
# elif defined(CONFIG_ARCH_OMAP2)
2006-04-02 17:46:21 +01:00
2006-06-26 16:16:12 -07:00
struct clk * omap_dm_timer_get_fclk ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-09-25 12:41:35 +03:00
return timer - > fclk ;
2006-06-26 16:16:12 -07:00
}
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
__u32 omap_dm_timer_modify_idlect_mask ( __u32 inputmask )
{
BUG ( ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
# endif
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
void omap_dm_timer_trigger ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_TRIGGER_REG , 0 ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_start ( struct omap_dm_timer * timer )
{
u32 l ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
if ( ! ( l & OMAP_TIMER_CTRL_ST ) ) {
l | = OMAP_TIMER_CTRL_ST ;
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
}
}
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
void omap_dm_timer_stop ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
u32 l ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
if ( l & OMAP_TIMER_CTRL_ST ) {
l & = ~ 0x1 ;
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
2005-09-07 17:20:26 +01:00
}
}
2006-06-26 16:16:12 -07:00
# ifdef CONFIG_ARCH_OMAP1
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_source ( struct omap_dm_timer * timer , int source )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
int n = ( timer - dm_timers ) < < 1 ;
u32 l ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
l = omap_readl ( MOD_CONF_CTRL_1 ) & ~ ( 0x03 < < n ) ;
l | = source < < n ;
omap_writel ( l , MOD_CONF_CTRL_1 ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
# else
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_source ( struct omap_dm_timer * timer , int source )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
if ( source < 0 | | source > = 3 )
return ;
clk_disable ( timer - > fclk ) ;
2006-06-26 16:16:23 -07:00
clk_set_parent ( timer - > fclk , dm_source_clocks [ source ] ) ;
2006-06-26 16:16:12 -07:00
clk_enable ( timer - > fclk ) ;
/* When the functional clock disappears, too quick writes seem to
* cause an abort . */
2006-06-26 16:16:13 -07:00
__delay ( 15000 ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
# endif
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_load ( struct omap_dm_timer * timer , int autoreload ,
unsigned int load )
2005-09-07 17:20:26 +01:00
{
u32 l ;
2006-06-26 16:16:12 -07:00
2005-09-07 17:20:26 +01:00
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
2006-06-26 16:16:12 -07:00
if ( autoreload )
l | = OMAP_TIMER_CTRL_AR ;
else
l & = ~ OMAP_TIMER_CTRL_AR ;
2005-09-07 17:20:26 +01:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_LOAD_REG , load ) ;
omap_dm_timer_write_reg ( timer , OMAP_TIMER_TRIGGER_REG , 0 ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_match ( struct omap_dm_timer * timer , int enable ,
unsigned int match )
2005-09-07 17:20:26 +01:00
{
u32 l ;
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
2006-06-26 16:16:23 -07:00
if ( enable )
2006-06-26 16:16:12 -07:00
l | = OMAP_TIMER_CTRL_CE ;
else
l & = ~ OMAP_TIMER_CTRL_CE ;
2005-09-07 17:20:26 +01:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_MATCH_REG , match ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_pwm ( struct omap_dm_timer * timer , int def_on ,
int toggle , int trigger )
2005-09-07 17:20:26 +01:00
{
u32 l ;
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
2006-06-26 16:16:12 -07:00
l & = ~ ( OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
OMAP_TIMER_CTRL_PT | ( 0x03 < < 10 ) ) ;
if ( def_on )
l | = OMAP_TIMER_CTRL_SCPWM ;
if ( toggle )
l | = OMAP_TIMER_CTRL_PT ;
l | = trigger < < 10 ;
2005-09-07 17:20:26 +01:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_prescaler ( struct omap_dm_timer * timer , int prescaler )
2005-09-07 17:20:26 +01:00
{
u32 l ;
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) ;
2006-06-26 16:16:12 -07:00
l & = ~ ( OMAP_TIMER_CTRL_PRE | ( 0x07 < < 2 ) ) ;
if ( prescaler > = 0x00 & & prescaler < = 0x07 ) {
l | = OMAP_TIMER_CTRL_PRE ;
l | = prescaler < < 2 ;
}
2005-09-07 17:20:26 +01:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_CTRL_REG , l ) ;
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_set_int_enable ( struct omap_dm_timer * timer ,
unsigned int value )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_INT_EN_REG , value ) ;
2006-09-25 12:41:44 +03:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_WAKEUP_EN_REG , value ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
unsigned int omap_dm_timer_read_status ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-09-25 12:41:35 +03:00
unsigned int l ;
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_STAT_REG ) ;
return l ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
void omap_dm_timer_write_status ( struct omap_dm_timer * timer , unsigned int value )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_STAT_REG , value ) ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:12 -07:00
unsigned int omap_dm_timer_read_counter ( struct omap_dm_timer * timer )
2005-09-07 17:20:26 +01:00
{
2006-09-25 12:41:35 +03:00
unsigned int l ;
l = omap_dm_timer_read_reg ( timer , OMAP_TIMER_COUNTER_REG ) ;
return l ;
2005-09-07 17:20:26 +01:00
}
2006-06-26 16:16:23 -07:00
void omap_dm_timer_write_counter ( struct omap_dm_timer * timer , unsigned int value )
{
2006-09-25 12:41:35 +03:00
omap_dm_timer_write_reg ( timer , OMAP_TIMER_COUNTER_REG , value ) ;
2006-06-26 16:16:23 -07:00
}
2006-06-26 16:16:12 -07:00
int omap_dm_timers_active ( void )
2005-09-07 17:20:26 +01:00
{
2006-06-26 16:16:12 -07:00
int i ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
for ( i = 0 ; i < dm_timer_count ; i + + ) {
struct omap_dm_timer * timer ;
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
timer = & dm_timers [ i ] ;
2006-09-25 12:41:42 +03:00
if ( ! timer - > enabled )
continue ;
2006-06-26 16:16:12 -07:00
if ( omap_dm_timer_read_reg ( timer , OMAP_TIMER_CTRL_REG ) &
2006-09-25 12:41:35 +03:00
OMAP_TIMER_CTRL_ST ) {
2006-06-26 16:16:12 -07:00
return 1 ;
2006-09-25 12:41:35 +03:00
}
2006-06-26 16:16:12 -07:00
}
return 0 ;
}
2005-09-07 17:20:26 +01:00
2006-06-26 16:16:12 -07:00
int omap_dm_timer_init ( void )
2005-09-07 17:20:26 +01:00
{
struct omap_dm_timer * timer ;
2006-06-26 16:16:12 -07:00
int i ;
if ( ! ( cpu_is_omap16xx ( ) | | cpu_is_omap24xx ( ) ) )
return - ENODEV ;
2005-09-07 17:20:26 +01:00
spin_lock_init ( & dm_timer_lock ) ;
2006-06-26 16:16:23 -07:00
# ifdef CONFIG_ARCH_OMAP2
for ( i = 0 ; i < ARRAY_SIZE ( dm_source_names ) ; i + + ) {
dm_source_clocks [ i ] = clk_get ( NULL , dm_source_names [ i ] ) ;
BUG_ON ( dm_source_clocks [ i ] = = NULL ) ;
}
# endif
2006-06-26 16:16:12 -07:00
for ( i = 0 ; i < dm_timer_count ; i + + ) {
# ifdef CONFIG_ARCH_OMAP2
char clk_name [ 16 ] ;
# endif
timer = & dm_timers [ i ] ;
timer - > io_base = ( void __iomem * ) io_p2v ( timer - > phys_base ) ;
# ifdef CONFIG_ARCH_OMAP2
sprintf ( clk_name , " gpt%d_ick " , i + 1 ) ;
timer - > iclk = clk_get ( NULL , clk_name ) ;
sprintf ( clk_name , " gpt%d_fck " , i + 1 ) ;
timer - > fclk = clk_get ( NULL , clk_name ) ;
# endif
2005-09-07 17:20:26 +01:00
}
return 0 ;
}