2005-04-17 02:20:36 +04:00
/*
* arch / sh / kernel / cpufreq . c
*
* cpufreq driver for the SuperH processors .
*
2007-07-20 08:38:19 +04:00
* Copyright ( C ) 2002 - 2007 Paul Mundt
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 2002 M . R . Brown
*
2007-07-20 08:38:19 +04:00
* Clock framework bits from arch / avr32 / mach - at32ap / cpufreq . c
*
* Copyright ( C ) 2004 - 2007 Atmel Corporation
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
2005-04-17 02:20:36 +04:00
*/
# include <linux/types.h>
# include <linux/cpufreq.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
2007-07-20 08:38:19 +04:00
# include <linux/err.h>
2005-04-17 02:20:36 +04:00
# include <linux/cpumask.h>
# include <linux/smp.h>
2005-10-31 02:03:48 +03:00
# include <linux/sched.h> /* set_cpus_allowed() */
2007-07-20 08:38:19 +04:00
# include <linux/clk.h>
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
static struct clk * cpuclk ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
static unsigned int sh_cpufreq_get ( unsigned int cpu )
2005-04-17 02:20:36 +04:00
{
2007-07-20 08:38:19 +04:00
return ( clk_get_rate ( cpuclk ) + 500 ) / 1000 ;
2005-04-17 02:20:36 +04:00
}
/*
* Here we notify other drivers of the proposed change and the final change .
*/
2007-07-20 08:38:19 +04:00
static int sh_cpufreq_target ( struct cpufreq_policy * policy ,
unsigned int target_freq ,
unsigned int relation )
2005-04-17 02:20:36 +04:00
{
2007-07-20 08:38:19 +04:00
unsigned int cpu = policy - > cpu ;
2005-04-17 02:20:36 +04:00
cpumask_t cpus_allowed ;
struct cpufreq_freqs freqs ;
2007-07-20 08:38:19 +04:00
long freq ;
2005-04-17 02:20:36 +04:00
if ( ! cpu_online ( cpu ) )
return - ENODEV ;
cpus_allowed = current - > cpus_allowed ;
2010-03-27 01:03:49 +03:00
set_cpus_allowed_ptr ( current , cpumask_of ( cpu ) ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( smp_processor_id ( ) ! = cpu ) ;
2007-07-20 08:38:19 +04:00
/* Convert target_freq from kHz to Hz */
freq = clk_round_rate ( cpuclk , target_freq * 1000 ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
if ( freq < ( policy - > min * 1000 ) | | freq > ( policy - > max * 1000 ) )
return - EINVAL ;
pr_debug ( " cpufreq: requested frequency %u Hz \n " , target_freq * 1000 ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
freqs . cpu = cpu ;
freqs . old = sh_cpufreq_get ( cpu ) ;
freqs . new = ( freq + 500 ) / 1000 ;
freqs . flags = 0 ;
cpufreq_notify_transition ( & freqs , CPUFREQ_PRECHANGE ) ;
2010-03-27 01:03:49 +03:00
set_cpus_allowed_ptr ( current , & cpus_allowed ) ;
2007-07-20 08:38:19 +04:00
clk_set_rate ( cpuclk , freq ) ;
2005-04-17 02:20:36 +04:00
cpufreq_notify_transition ( & freqs , CPUFREQ_POSTCHANGE ) ;
2007-07-20 08:38:19 +04:00
pr_debug ( " cpufreq: set frequency %lu Hz \n " , freq ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int sh_cpufreq_cpu_init ( struct cpufreq_policy * policy )
{
if ( ! cpu_online ( policy - > cpu ) )
return - ENODEV ;
2007-07-20 08:38:19 +04:00
cpuclk = clk_get ( NULL , " cpu_clk " ) ;
if ( IS_ERR ( cpuclk ) ) {
2009-09-15 04:26:04 +04:00
printk ( KERN_ERR " cpufreq: couldn't get CPU#%d clk \n " ,
policy - > cpu ) ;
2007-07-20 08:38:19 +04:00
return PTR_ERR ( cpuclk ) ;
}
2005-04-17 02:20:36 +04:00
/* cpuinfo and default policy values */
2007-07-20 08:38:19 +04:00
policy - > cpuinfo . min_freq = ( clk_round_rate ( cpuclk , 1 ) + 500 ) / 1000 ;
policy - > cpuinfo . max_freq = ( clk_round_rate ( cpuclk , ~ 0UL ) + 500 ) / 1000 ;
2005-04-17 02:20:36 +04:00
policy - > cpuinfo . transition_latency = CPUFREQ_ETERNAL ;
2007-07-20 08:38:19 +04:00
policy - > cur = sh_cpufreq_get ( policy - > cpu ) ;
policy - > min = policy - > cpuinfo . min_freq ;
policy - > max = policy - > cpuinfo . max_freq ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
/*
* Catch the cases where the clock framework hasn ' t been wired up
* properly to support scaling .
*/
if ( unlikely ( policy - > min = = policy - > max ) ) {
printk ( KERN_ERR " cpufreq: clock framework rate rounding "
2009-09-15 04:26:04 +04:00
" not supported on CPU#%d. \n " , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
clk_put ( cpuclk ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-07-20 08:38:19 +04:00
}
2005-04-17 02:20:36 +04:00
2009-09-15 04:26:04 +04:00
printk ( KERN_INFO " cpufreq: CPU#%d Frequencies - Minimum %u.%03u MHz, "
2007-07-20 08:38:19 +04:00
" Maximum %u.%03u MHz. \n " ,
2009-09-15 04:26:04 +04:00
policy - > cpu , policy - > min / 1000 , policy - > min % 1000 ,
2007-07-20 08:38:19 +04:00
policy - > max / 1000 , policy - > max % 1000 ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-07-20 08:38:19 +04:00
static int sh_cpufreq_verify ( struct cpufreq_policy * policy )
{
cpufreq_verify_within_limits ( policy , policy - > cpuinfo . min_freq ,
policy - > cpuinfo . max_freq ) ;
return 0 ;
}
static int sh_cpufreq_exit ( struct cpufreq_policy * policy )
{
clk_put ( cpuclk ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static struct cpufreq_driver sh_cpufreq_driver = {
. owner = THIS_MODULE ,
2007-07-20 08:38:19 +04:00
. name = " sh " ,
2005-04-17 02:20:36 +04:00
. init = sh_cpufreq_cpu_init ,
. verify = sh_cpufreq_verify ,
. target = sh_cpufreq_target ,
2007-07-20 08:38:19 +04:00
. get = sh_cpufreq_get ,
. exit = sh_cpufreq_exit ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-20 08:38:19 +04:00
static int __init sh_cpufreq_module_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-09-21 12:53:26 +04:00
printk ( KERN_INFO " cpufreq: SuperH CPU frequency driver. \n " ) ;
2007-07-20 08:38:19 +04:00
return cpufreq_register_driver ( & sh_cpufreq_driver ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 08:38:19 +04:00
static void __exit sh_cpufreq_module_exit ( void )
2005-04-17 02:20:36 +04:00
{
cpufreq_unregister_driver ( & sh_cpufreq_driver ) ;
}
2007-07-20 08:38:19 +04:00
module_init ( sh_cpufreq_module_init ) ;
module_exit ( sh_cpufreq_module_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Paul Mundt <lethal@linux-sh.org> " ) ;
MODULE_DESCRIPTION ( " cpufreq driver for SuperH " ) ;
MODULE_LICENSE ( " GPL " ) ;