2013-01-22 02:51:08 +04:00
/*
2009-11-14 01:54:14 +03:00
* Copyright ( c ) 2006 - 2008 Simtec Electronics
2009-07-31 02:23:27 +04:00
* http : //armlinux.simtec.co.uk/
* Ben Dooks < ben @ simtec . co . uk >
*
* S3C2410 CPU Frequency scaling
*
* 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 .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/cpufreq.h>
2011-12-22 04:01:38 +04:00
# include <linux/device.h>
2009-07-31 02:23:27 +04:00
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <asm/mach/arch.h>
# include <asm/mach/map.h>
# include <mach/regs-clock.h>
# include <plat/cpu.h>
# include <plat/cpu-freq-core.h>
/* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */
static void s3c2410_cpufreq_setdivs ( struct s3c_cpufreq_config * cfg )
{
u32 clkdiv = 0 ;
if ( cfg - > divs . h_divisor = = 2 )
clkdiv | = S3C2410_CLKDIVN_HDIVN ;
if ( cfg - > divs . p_divisor ! = cfg - > divs . h_divisor )
clkdiv | = S3C2410_CLKDIVN_PDIVN ;
__raw_writel ( clkdiv , S3C2410_CLKDIVN ) ;
}
static int s3c2410_cpufreq_calcdivs ( struct s3c_cpufreq_config * cfg )
{
unsigned long hclk , fclk , pclk ;
unsigned int hdiv , pdiv ;
unsigned long hclk_max ;
fclk = cfg - > freq . fclk ;
hclk_max = cfg - > max . hclk ;
cfg - > freq . armclk = fclk ;
s3c_freq_dbg ( " %s: fclk is %lu, max hclk %lu \n " ,
__func__ , fclk , hclk_max ) ;
hdiv = ( fclk > cfg - > max . hclk ) ? 2 : 1 ;
hclk = fclk / hdiv ;
if ( hclk > cfg - > max . hclk ) {
s3c_freq_dbg ( " %s: hclk too big \n " , __func__ ) ;
return - EINVAL ;
}
pdiv = ( hclk > cfg - > max . pclk ) ? 2 : 1 ;
pclk = hclk / pdiv ;
if ( pclk > cfg - > max . pclk ) {
s3c_freq_dbg ( " %s: pclk too big \n " , __func__ ) ;
return - EINVAL ;
}
pdiv * = hdiv ;
/* record the result */
cfg - > divs . p_divisor = pdiv ;
cfg - > divs . h_divisor = hdiv ;
2013-01-22 02:51:08 +04:00
return 0 ;
2009-07-31 02:23:27 +04:00
}
static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
. max = {
. fclk = 200000000 ,
. hclk = 100000000 ,
. pclk = 50000000 ,
} ,
/* transition latency is about 5ms worst-case, so
* set 10 ms to be sure */
. latency = 10000000 ,
. locktime_m = 150 ,
. locktime_u = 150 ,
. locktime_bits = 12 ,
. need_pll = 1 ,
. name = " s3c2410 " ,
. calc_iotiming = s3c2410_iotiming_calc ,
. set_iotiming = s3c2410_iotiming_set ,
. get_iotiming = s3c2410_iotiming_get ,
. set_fvco = s3c2410_set_fvco ,
. set_refresh = s3c2410_cpufreq_setrefresh ,
. set_divs = s3c2410_cpufreq_setdivs ,
. calc_divs = s3c2410_cpufreq_calcdivs ,
2009-07-31 02:23:42 +04:00
. debug_io_show = s3c_cpufreq_debugfs_call ( s3c2410_iotiming_debugfs ) ,
2009-07-31 02:23:27 +04:00
} ;
2012-01-27 10:35:25 +04:00
static int s3c2410_cpufreq_add ( struct device * dev ,
struct subsys_interface * sif )
2009-07-31 02:23:27 +04:00
{
return s3c_cpufreq_register ( & s3c2410_cpufreq_info ) ;
}
2011-12-22 04:01:38 +04:00
static struct subsys_interface s3c2410_cpufreq_interface = {
. name = " s3c2410_cpufreq " ,
. subsys = & s3c2410_subsys ,
. add_dev = s3c2410_cpufreq_add ,
2009-07-31 02:23:27 +04:00
} ;
static int __init s3c2410_cpufreq_init ( void )
{
2011-12-22 04:01:38 +04:00
return subsys_interface_register ( & s3c2410_cpufreq_interface ) ;
2009-07-31 02:23:27 +04:00
}
arch_initcall ( s3c2410_cpufreq_init ) ;
2012-01-27 10:35:25 +04:00
static int s3c2410a_cpufreq_add ( struct device * dev ,
struct subsys_interface * sif )
2009-07-31 02:23:27 +04:00
{
/* alter the maximum freq settings for S3C2410A. If a board knows
* it only has a maximum of 200 , then it should register its own
* limits . */
s3c2410_cpufreq_info . max . fclk = 266000000 ;
s3c2410_cpufreq_info . max . hclk = 133000000 ;
s3c2410_cpufreq_info . max . pclk = 66500000 ;
s3c2410_cpufreq_info . name = " s3c2410a " ;
2012-01-27 10:35:25 +04:00
return s3c2410_cpufreq_add ( dev , sif ) ;
2009-07-31 02:23:27 +04:00
}
2011-12-22 04:01:38 +04:00
static struct subsys_interface s3c2410a_cpufreq_interface = {
. name = " s3c2410a_cpufreq " ,
. subsys = & s3c2410a_subsys ,
. add_dev = s3c2410a_cpufreq_add ,
2009-07-31 02:23:27 +04:00
} ;
static int __init s3c2410a_cpufreq_init ( void )
{
2011-12-22 04:01:38 +04:00
return subsys_interface_register ( & s3c2410a_cpufreq_interface ) ;
2009-07-31 02:23:27 +04:00
}
arch_initcall ( s3c2410a_cpufreq_init ) ;