2010-12-08 15:13:42 +01:00
/*
* Copyright ( C ) STMicroelectronics 2009
2012-11-28 11:27:44 +01:00
* Copyright ( C ) ST - Ericsson SA 2010 - 2012
2010-12-08 15:13:42 +01:00
*
* License Terms : GNU General Public License v2
* Author : Sundar Iyer < sundar . iyer @ stericsson . com >
* Author : Martin Persson < martin . persson @ stericsson . com >
* Author : Jonas Aaberg < jonas . aberg @ stericsson . com >
*/
2012-11-28 11:27:44 +01:00
2012-10-10 13:42:24 +02:00
# include <linux/module.h>
2010-12-08 15:13:42 +01:00
# include <linux/kernel.h>
# include <linux/cpufreq.h>
# include <linux/delay.h>
2011-05-15 19:19:51 +02:00
# include <linux/slab.h>
2012-10-10 13:42:24 +02:00
# include <linux/platform_device.h>
2012-10-10 13:42:29 +02:00
# include <linux/clk.h>
2010-12-08 15:13:42 +01:00
2012-10-10 13:42:25 +02:00
static struct cpufreq_frequency_table * freq_table ;
2012-10-10 13:42:29 +02:00
static struct clk * armss_clk ;
2011-05-15 19:19:51 +02:00
2012-12-10 16:25:38 +01:00
static int dbx500_cpufreq_target ( struct cpufreq_policy * policy ,
2010-12-08 15:13:42 +01:00
unsigned int target_freq ,
unsigned int relation )
{
struct cpufreq_freqs freqs ;
2011-05-15 19:19:51 +02:00
unsigned int idx ;
2012-11-28 11:27:43 +01:00
int ret ;
2010-12-08 15:13:42 +01:00
2011-05-15 19:19:51 +02:00
/* Lookup the next frequency */
2012-11-28 11:27:43 +01:00
if ( cpufreq_frequency_table_target ( policy , freq_table , target_freq ,
relation , & idx ) )
2011-05-15 19:19:51 +02:00
return - EINVAL ;
2010-12-08 15:13:42 +01:00
freqs . old = policy - > cur ;
2011-05-15 19:19:51 +02:00
freqs . new = freq_table [ idx ] . frequency ;
2010-12-08 15:13:42 +01:00
2011-05-15 19:19:51 +02:00
if ( freqs . old = = freqs . new )
2010-12-08 15:13:42 +01:00
return 0 ;
2011-05-15 19:19:51 +02:00
/* pre-change notification */
2013-03-24 11:56:43 +05:30
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_PRECHANGE ) ;
2010-12-08 15:13:42 +01:00
2012-10-10 13:42:29 +02:00
/* update armss clk frequency */
2012-11-28 11:27:43 +01:00
ret = clk_set_rate ( armss_clk , freqs . new * 1000 ) ;
if ( ret ) {
pr_err ( " dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d \n " ,
freqs . new * 1000 , ret ) ;
2013-06-19 11:18:20 +05:30
freqs . new = freqs . old ;
2010-12-08 15:13:42 +01:00
}
2011-05-15 19:19:51 +02:00
/* post change notification */
2013-03-24 11:56:43 +05:30
cpufreq_notify_transition ( policy , & freqs , CPUFREQ_POSTCHANGE ) ;
2010-12-08 15:13:42 +01:00
2013-06-19 11:18:20 +05:30
return ret ;
2010-12-08 15:13:42 +01:00
}
2012-12-10 16:25:38 +01:00
static unsigned int dbx500_cpufreq_getspeed ( unsigned int cpu )
2010-12-08 15:13:42 +01:00
{
2012-10-10 13:42:25 +02:00
int i = 0 ;
2012-10-10 13:42:29 +02:00
unsigned long freq = clk_get_rate ( armss_clk ) / 1000 ;
2012-10-10 13:42:25 +02:00
2013-04-11 23:23:57 +02:00
/* The value is rounded to closest frequency in the defined table. */
while ( freq_table [ i + 1 ] . frequency ! = CPUFREQ_TABLE_END ) {
if ( freq < freq_table [ i ] . frequency +
( freq_table [ i + 1 ] . frequency - freq_table [ i ] . frequency ) / 2 )
2012-10-10 13:42:25 +02:00
return freq_table [ i ] . frequency ;
i + + ;
}
2013-04-11 23:23:57 +02:00
return freq_table [ i ] . frequency ;
2010-12-08 15:13:42 +01:00
}
2013-06-19 13:54:04 -04:00
static int dbx500_cpufreq_init ( struct cpufreq_policy * policy )
2010-12-08 15:13:42 +01:00
{
2012-10-10 13:42:25 +02:00
int res ;
2012-01-13 16:20:03 +01:00
2010-12-08 15:13:42 +01:00
/* get policy fields based on the table */
2013-09-16 18:56:13 +05:30
res = cpufreq_table_validate_and_show ( policy , freq_table ) ;
if ( res ) {
2012-11-28 11:27:43 +01:00
pr_err ( " dbx500-cpufreq: Failed to read policy table \n " ) ;
2010-12-08 15:13:42 +01:00
return res ;
}
/*
* FIXME : Need to take time measurement across the target ( )
* function with no / some / all drivers in the notification
* list .
*/
2011-05-15 19:19:51 +02:00
policy - > cpuinfo . transition_latency = 20 * 1000 ; /* in ns */
2010-12-08 15:13:42 +01:00
/* policy sharing between dual CPUs */
2013-02-01 06:40:01 +00:00
cpumask_setall ( policy - > cpus ) ;
2010-12-08 15:13:42 +01:00
return 0 ;
}
2012-12-10 16:25:38 +01:00
static struct cpufreq_driver dbx500_cpufreq_driver = {
2012-12-04 11:10:45 +01:00
. flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS ,
2013-10-03 20:28:03 +05:30
. verify = cpufreq_generic_frequency_table_verify ,
2012-12-10 16:25:38 +01:00
. target = dbx500_cpufreq_target ,
. get = dbx500_cpufreq_getspeed ,
. init = dbx500_cpufreq_init ,
. name = " DBX500 " ,
2013-10-03 20:28:03 +05:30
. attr = cpufreq_generic_attr ,
2010-12-08 15:13:42 +01:00
} ;
2012-12-10 16:25:38 +01:00
static int dbx500_cpufreq_probe ( struct platform_device * pdev )
2012-10-10 13:42:24 +02:00
{
2012-12-10 16:25:40 +01:00
int i = 0 ;
2012-10-10 13:42:25 +02:00
2012-12-10 16:25:40 +01:00
freq_table = dev_get_platdata ( & pdev - > dev ) ;
2012-10-10 13:42:25 +02:00
if ( ! freq_table ) {
2012-12-10 16:25:38 +01:00
pr_err ( " dbx500-cpufreq: Failed to fetch cpufreq table \n " ) ;
2012-10-10 13:42:25 +02:00
return - ENODEV ;
}
2012-12-10 16:25:40 +01:00
armss_clk = clk_get ( & pdev - > dev , " armss " ) ;
if ( IS_ERR ( armss_clk ) ) {
2012-11-28 11:27:43 +01:00
pr_err ( " dbx500-cpufreq: Failed to get armss clk \n " ) ;
2012-12-10 16:25:40 +01:00
return PTR_ERR ( armss_clk ) ;
}
2012-11-28 11:27:43 +01:00
pr_info ( " dbx500-cpufreq: Available frequencies: \n " ) ;
2012-12-10 16:25:40 +01:00
while ( freq_table [ i ] . frequency ! = CPUFREQ_TABLE_END ) {
pr_info ( " %d Mhz \n " , freq_table [ i ] . frequency / 1000 ) ;
i + + ;
}
2012-12-10 16:25:38 +01:00
return cpufreq_register_driver ( & dbx500_cpufreq_driver ) ;
2012-10-10 13:42:24 +02:00
}
2012-12-10 16:25:38 +01:00
static struct platform_driver dbx500_cpufreq_plat_driver = {
2012-10-10 13:42:24 +02:00
. driver = {
2012-12-10 16:25:38 +01:00
. name = " cpufreq-ux500 " ,
2012-10-10 13:42:24 +02:00
. owner = THIS_MODULE ,
} ,
2012-12-10 16:25:38 +01:00
. probe = dbx500_cpufreq_probe ,
2012-10-10 13:42:24 +02:00
} ;
2012-12-10 16:25:38 +01:00
static int __init dbx500_cpufreq_register ( void )
2010-12-08 15:13:42 +01:00
{
2012-12-10 16:25:38 +01:00
return platform_driver_register ( & dbx500_cpufreq_plat_driver ) ;
2010-12-08 15:13:42 +01:00
}
2012-12-10 16:25:38 +01:00
device_initcall ( dbx500_cpufreq_register ) ;
2012-10-10 13:42:24 +02:00
MODULE_LICENSE ( " GPL v2 " ) ;
2012-12-10 16:25:38 +01:00
MODULE_DESCRIPTION ( " cpufreq driver for DBX500 " ) ;