2005-04-16 15:20:36 -07:00
/*
2005-07-10 19:58:14 +01:00
* linux / arch / arm / plat - omap / clock . c
2005-04-16 15:20:36 -07:00
*
2005-11-10 14:26:50 +00:00
* Copyright ( C ) 2004 - 2005 Nokia corporation
2005-04-16 15:20:36 -07:00
* Written by Tuukka Tikkanen < tuukka . tikkanen @ elektrobit . com >
*
2005-11-10 14:26:50 +00:00
* Modified for omap shared clock framework by Tony Lindgren < tony @ atomide . com >
*
2005-04-16 15:20:36 -07: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 .
*/
2005-11-10 14:26:50 +00:00
# include <linux/version.h>
# include <linux/config.h>
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
2005-11-10 14:26:50 +00:00
# include <linux/init.h>
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
2006-01-07 16:15:52 +00:00
# include <linux/clk.h>
2006-01-12 18:42:23 +00:00
# include <linux/mutex.h>
2006-04-02 17:46:20 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
2005-07-10 19:58:18 +01:00
# include <asm/io.h>
2005-04-16 15:20:36 -07:00
# include <asm/semaphore.h>
2005-11-10 14:26:50 +00:00
# include <asm/arch/clock.h>
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
LIST_HEAD ( clocks ) ;
2006-01-12 18:42:23 +00:00
static DEFINE_MUTEX ( clocks_mutex ) ;
2005-11-10 14:26:50 +00:00
DEFINE_SPINLOCK ( clockfw_lock ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
static struct clk_functions * arch_clock ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
/*-------------------------------------------------------------------------
2006-01-17 15:27:09 -08:00
* Standard clock functions defined in include / linux / clk . h
2005-11-10 14:26:50 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
/*
* Returns a clock . Note that we first try to use device id on the bus
* and clock name . If this fails , we try to use clock name only .
*/
2005-11-10 14:26:50 +00:00
struct clk * clk_get ( struct device * dev , const char * id )
2005-04-16 15:20:36 -07:00
{
struct clk * p , * clk = ERR_PTR ( - ENOENT ) ;
2006-04-02 17:46:20 +01:00
int idno ;
if ( dev = = NULL | | dev - > bus ! = & platform_bus_type )
idno = - 1 ;
else
idno = to_platform_device ( dev ) - > id ;
2005-04-16 15:20:36 -07:00
2006-01-12 18:42:23 +00:00
mutex_lock ( & clocks_mutex ) ;
2006-04-02 17:46:20 +01:00
list_for_each_entry ( p , & clocks , node ) {
if ( p - > id = = idno & &
strcmp ( id , p - > name ) = = 0 & & try_module_get ( p - > owner ) ) {
clk = p ;
2006-04-09 22:21:05 +01:00
goto found ;
2006-04-02 17:46:20 +01:00
}
}
2005-04-16 15:20:36 -07:00
list_for_each_entry ( p , & clocks , node ) {
if ( strcmp ( id , p - > name ) = = 0 & & try_module_get ( p - > owner ) ) {
clk = p ;
break ;
}
}
2006-04-02 17:46:20 +01:00
2006-04-09 22:21:05 +01:00
found :
2006-01-12 18:42:23 +00:00
mutex_unlock ( & clocks_mutex ) ;
2005-04-16 15:20:36 -07:00
return clk ;
}
EXPORT_SYMBOL ( clk_get ) ;
int clk_enable ( struct clk * clk )
{
unsigned long flags ;
2005-11-10 14:26:50 +00:00
int ret = 0 ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
2006-01-17 15:27:09 -08:00
if ( arch_clock - > clk_enable )
2005-11-10 14:26:50 +00:00
ret = arch_clock - > clk_enable ( clk ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-11-10 14:26:50 +00:00
2005-04-16 15:20:36 -07:00
return ret ;
}
EXPORT_SYMBOL ( clk_enable ) ;
void clk_disable ( struct clk * clk )
{
unsigned long flags ;
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
2006-01-17 15:27:09 -08:00
if ( arch_clock - > clk_disable )
2005-11-10 14:26:50 +00:00
arch_clock - > clk_disable ( clk ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
}
EXPORT_SYMBOL ( clk_disable ) ;
int clk_get_usecount ( struct clk * clk )
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
int ret = 0 ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return 0 ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
ret = clk - > usecount ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_get_usecount ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
unsigned long clk_get_rate ( struct clk * clk )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
unsigned long ret = 0 ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return 0 ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
ret = clk - > rate ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_get_rate ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
void clk_put ( struct clk * clk )
2005-07-10 19:58:18 +01:00
{
2005-11-10 14:26:50 +00:00
if ( clk & & ! IS_ERR ( clk ) )
module_put ( clk - > owner ) ;
2005-07-10 19:58:18 +01:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_put ) ;
2005-07-10 19:58:18 +01:00
2005-11-10 14:26:50 +00:00
/*-------------------------------------------------------------------------
2006-01-17 15:27:09 -08:00
* Optional clock functions defined in include / linux / clk . h
2005-11-10 14:26:50 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-07-10 19:58:18 +01:00
2005-04-16 15:20:36 -07:00
long clk_round_rate ( struct clk * clk , unsigned long rate )
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
long ret = 0 ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ret ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_round_rate )
ret = arch_clock - > clk_round_rate ( clk , rate ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
EXPORT_SYMBOL ( clk_round_rate ) ;
2005-11-10 14:26:50 +00:00
int clk_set_rate ( struct clk * clk , unsigned long rate )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
2006-04-02 17:46:20 +01:00
int ret = - EINVAL ;
if ( clk = = NULL | | IS_ERR ( clk ) )
return ret ;
2005-07-10 19:58:18 +01:00
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_set_rate )
ret = arch_clock - > clk_set_rate ( clk , rate ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_set_rate ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
int clk_set_parent ( struct clk * clk , struct clk * parent )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
2006-04-02 17:46:20 +01:00
int ret = - EINVAL ;
if ( clk = = NULL | | IS_ERR ( clk ) | | parent = = NULL | | IS_ERR ( parent ) )
return ret ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_set_parent )
ret = arch_clock - > clk_set_parent ( clk , parent ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_set_parent ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
struct clk * clk_get_parent ( struct clk * clk )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
struct clk * ret = NULL ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ret ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_get_parent )
ret = arch_clock - > clk_get_parent ( clk ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_get_parent ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
/*-------------------------------------------------------------------------
* OMAP specific clock functions shared between omap1 and omap2
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
unsigned int __initdata mpurate ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
/*
* By default we use the rate set by the bootloader .
* You can override this with mpurate = cmdline option .
*/
static int __init omap_clk_setup ( char * str )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
get_option ( & str , & mpurate ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
if ( ! mpurate )
return 1 ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
if ( mpurate < 1000 )
mpurate * = 1000000 ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
return 1 ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
__setup ( " mpurate= " , omap_clk_setup ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc ( struct clk * clk )
2005-04-16 15:20:36 -07:00
{
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ;
2005-11-10 14:26:50 +00:00
clk - > rate = clk - > parent - > rate ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
/* Propagate rate to children */
void propagate_rate ( struct clk * tclk )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
struct clk * clkp ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( tclk = = NULL | | IS_ERR ( tclk ) )
return ;
2005-11-10 14:26:50 +00:00
list_for_each_entry ( clkp , & clocks , node ) {
if ( likely ( clkp - > parent ! = tclk ) )
continue ;
if ( likely ( ( u32 ) clkp - > recalc ) )
clkp - > recalc ( clkp ) ;
}
2005-04-16 15:20:36 -07:00
}
int clk_register ( struct clk * clk )
{
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return - EINVAL ;
2006-01-12 18:42:23 +00:00
mutex_lock ( & clocks_mutex ) ;
2005-04-16 15:20:36 -07:00
list_add ( & clk - > node , & clocks ) ;
if ( clk - > init )
clk - > init ( clk ) ;
2006-01-12 18:42:23 +00:00
mutex_unlock ( & clocks_mutex ) ;
2005-11-10 14:26:50 +00:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
EXPORT_SYMBOL ( clk_register ) ;
void clk_unregister ( struct clk * clk )
{
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ;
2006-01-12 18:42:23 +00:00
mutex_lock ( & clocks_mutex ) ;
2005-04-16 15:20:36 -07:00
list_del ( & clk - > node ) ;
2006-01-12 18:42:23 +00:00
mutex_unlock ( & clocks_mutex ) ;
2005-04-16 15:20:36 -07:00
}
EXPORT_SYMBOL ( clk_unregister ) ;
2005-11-10 14:26:50 +00:00
void clk_deny_idle ( struct clk * clk )
2005-07-10 19:58:18 +01:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_deny_idle )
arch_clock - > clk_deny_idle ( clk ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-07-10 19:58:18 +01:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_deny_idle ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 14:26:50 +00:00
void clk_allow_idle ( struct clk * clk )
2005-04-16 15:20:36 -07:00
{
2005-11-10 14:26:50 +00:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-04-02 17:46:20 +01:00
if ( clk = = NULL | | IS_ERR ( clk ) )
return ;
2005-11-10 14:26:50 +00:00
spin_lock_irqsave ( & clockfw_lock , flags ) ;
if ( arch_clock - > clk_allow_idle )
arch_clock - > clk_allow_idle ( clk ) ;
spin_unlock_irqrestore ( & clockfw_lock , flags ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-10 14:26:50 +00:00
EXPORT_SYMBOL ( clk_allow_idle ) ;
2005-07-10 19:58:18 +01:00
2005-11-10 14:26:50 +00:00
/*-------------------------------------------------------------------------*/
2005-07-10 19:58:18 +01:00
2005-11-10 14:26:50 +00:00
int __init clk_init ( struct clk_functions * custom_clocks )
2005-07-10 19:58:18 +01:00
{
2005-11-10 14:26:50 +00:00
if ( ! custom_clocks ) {
printk ( KERN_ERR " No custom clock functions registered \n " ) ;
BUG ( ) ;
2005-07-10 19:58:18 +01:00
}
2005-11-10 14:26:50 +00:00
arch_clock = custom_clocks ;
2005-07-10 19:58:18 +01:00
return 0 ;
}