2005-04-17 02:20:36 +04:00
/*
* cpufreq driver for the SuperH processors .
*
2012-01-27 12:49:16 +04:00
* Copyright ( C ) 2002 - 2012 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
*/
2012-01-27 14:44:49 +04:00
# define pr_fmt(fmt) "cpufreq: " fmt
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>
2012-01-27 14:44:49 +04:00
# include <linux/cpu.h>
2005-04-17 02:20:36 +04:00
# 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>
2012-01-27 12:49:16 +04:00
# include <linux/percpu.h>
# include <linux/sh_clk.h>
2005-04-17 02:20:36 +04:00
2012-01-27 12:49:16 +04:00
static DEFINE_PER_CPU ( struct clk , sh_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
{
2012-01-27 12:49:16 +04:00
return ( clk_get_rate ( & per_cpu ( sh_cpuclk , cpu ) ) + 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 ;
2012-01-27 12:49:16 +04:00
struct clk * cpuclk = & per_cpu ( sh_cpuclk , cpu ) ;
2005-04-17 02:20:36 +04:00
cpumask_t cpus_allowed ;
struct cpufreq_freqs freqs ;
2012-01-27 14:44:49 +04:00
struct device * dev ;
2007-07-20 08:38:19 +04:00
long freq ;
2005-04-17 02:20:36 +04:00
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 ) ;
2012-01-27 14:44:49 +04:00
dev = get_cpu_device ( 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 ;
2012-01-27 14:44:49 +04:00
dev_dbg ( dev , " 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 . old = sh_cpufreq_get ( cpu ) ;
freqs . new = ( freq + 500 ) / 1000 ;
freqs . flags = 0 ;
2014-03-24 12:05:45 +04:00
cpufreq_freq_transition_begin ( policy , & freqs ) ;
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 ) ;
2014-03-24 12:05:45 +04:00
cpufreq_freq_transition_end ( policy , & freqs , 0 ) ;
2005-04-17 02:20:36 +04:00
2012-01-27 14:44:49 +04:00
dev_dbg ( dev , " set frequency %lu Hz \n " , freq ) ;
2007-07-20 08:38:19 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-01-27 15:18:24 +04:00
static int sh_cpufreq_verify ( struct cpufreq_policy * policy )
{
struct clk * cpuclk = & per_cpu ( sh_cpuclk , policy - > cpu ) ;
struct cpufreq_frequency_table * freq_table ;
freq_table = cpuclk - > nr_freqs ? cpuclk - > freq_table : NULL ;
if ( freq_table )
return cpufreq_frequency_table_verify ( policy , freq_table ) ;
2013-10-02 12:43:19 +04:00
cpufreq_verify_within_cpu_limits ( policy ) ;
2012-01-27 15:18:24 +04:00
policy - > min = ( clk_round_rate ( cpuclk , 1 ) + 500 ) / 1000 ;
policy - > max = ( clk_round_rate ( cpuclk , ~ 0UL ) + 500 ) / 1000 ;
2013-10-02 12:43:19 +04:00
cpufreq_verify_within_cpu_limits ( policy ) ;
2012-01-27 15:18:24 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int sh_cpufreq_cpu_init ( struct cpufreq_policy * policy )
{
2012-01-27 12:49:16 +04:00
unsigned int cpu = policy - > cpu ;
struct clk * cpuclk = & per_cpu ( sh_cpuclk , cpu ) ;
2012-01-27 15:18:24 +04:00
struct cpufreq_frequency_table * freq_table ;
2012-01-27 14:44:49 +04:00
struct device * dev ;
2012-01-27 12:49:16 +04:00
2012-01-27 14:44:49 +04:00
dev = get_cpu_device ( cpu ) ;
cpuclk = clk_get ( dev , " cpu_clk " ) ;
2007-07-20 08:38:19 +04:00
if ( IS_ERR ( cpuclk ) ) {
2012-01-27 14:44:49 +04:00
dev_err ( dev , " couldn't get CPU clk \n " ) ;
2007-07-20 08:38:19 +04:00
return PTR_ERR ( cpuclk ) ;
}
2005-04-17 02:20:36 +04:00
2012-01-27 15:18:24 +04:00
freq_table = cpuclk - > nr_freqs ? cpuclk - > freq_table : NULL ;
if ( freq_table ) {
2012-01-27 15:43:14 +04:00
int result ;
2012-01-27 15:18:24 +04:00
2013-09-16 17:26:35 +04:00
result = cpufreq_table_validate_and_show ( policy , freq_table ) ;
if ( result )
return result ;
2012-01-27 15:18:24 +04:00
} else {
2012-01-27 15:43:14 +04:00
dev_notice ( dev , " no frequency table found, falling back "
" to rate rounding. \n " ) ;
2013-04-01 16:57:48 +04:00
policy - > min = policy - > cpuinfo . min_freq =
2012-01-27 15:43:14 +04:00
( clk_round_rate ( cpuclk , 1 ) + 500 ) / 1000 ;
2013-04-01 16:57:48 +04:00
policy - > max = policy - > cpuinfo . max_freq =
2012-01-27 15:43:14 +04:00
( clk_round_rate ( cpuclk , ~ 0UL ) + 500 ) / 1000 ;
2007-07-20 08:38:19 +04:00
}
2005-04-17 02:20:36 +04:00
2012-01-27 15:18:24 +04:00
policy - > cpuinfo . transition_latency = CPUFREQ_ETERNAL ;
2012-01-27 14:44:49 +04:00
dev_info ( dev , " CPU Frequencies - Minimum %u.%03u MHz, "
2007-07-20 08:38:19 +04:00
" Maximum %u.%03u MHz. \n " ,
2012-01-27 14:44:49 +04:00
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
2012-01-27 15:18:24 +04:00
static int sh_cpufreq_cpu_exit ( struct cpufreq_policy * policy )
2007-07-20 08:38:19 +04:00
{
2012-01-27 15:18:24 +04:00
unsigned int cpu = policy - > cpu ;
struct clk * cpuclk = & per_cpu ( sh_cpuclk , cpu ) ;
2007-07-20 08:38:19 +04:00
clk_put ( cpuclk ) ;
2012-01-27 15:18:24 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static struct cpufreq_driver sh_cpufreq_driver = {
2007-07-20 08:38:19 +04:00
. name = " sh " ,
. get = sh_cpufreq_get ,
2012-01-27 15:18:24 +04:00
. target = sh_cpufreq_target ,
. verify = sh_cpufreq_verify ,
. init = sh_cpufreq_cpu_init ,
. exit = sh_cpufreq_cpu_exit ,
2013-10-03 18:58:25 +04:00
. attr = cpufreq_generic_attr ,
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
{
2012-01-27 14:44:49 +04:00
pr_notice ( " 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 " ) ;