2010-05-29 20:32:23 +04:00
/*
* OMAP3 / OMAP4 smartreflex device file
*
* Author : Thara Gopinath < thara @ ti . com >
*
* Based originally on code from smartreflex . c
* Copyright ( C ) 2010 Texas Instruments , Inc .
* Thara Gopinath < thara @ ti . com >
*
* Copyright ( C ) 2008 Nokia Corporation
* Kalle Jokiniemi
*
* Copyright ( C ) 2007 Texas Instruments , Inc .
* Lesly A M < x0080970 @ ti . com >
*
* 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 .
*/
2012-04-25 14:36:20 +04:00
# include <linux/power/smartreflex.h>
2010-05-29 20:32:23 +04:00
# include <linux/err.h>
# include <linux/slab.h>
2010-08-18 10:53:12 +04:00
# include <linux/io.h>
2010-05-29 20:32:23 +04:00
2012-10-06 00:25:59 +04:00
# include "soc.h"
2012-10-03 04:25:48 +04:00
# include "omap_device.h"
2011-02-26 01:54:33 +03:00
# include "voltage.h"
2010-05-29 20:32:23 +04:00
# include "control.h"
2011-01-03 22:35:41 +03:00
# include "pm.h"
2010-05-29 20:32:23 +04:00
static bool sr_enable_on_init ;
/* Read EFUSE values from control registers for OMAP3430 */
static void __init sr_set_nvalues ( struct omap_volt_data * volt_data ,
struct omap_sr_data * sr_data )
{
struct omap_sr_nvalue_table * nvalue_table ;
2012-04-25 09:49:44 +04:00
int i , j , count = 0 ;
sr_data - > nvalue_count = 0 ;
sr_data - > nvalue_table = NULL ;
2010-05-29 20:32:23 +04:00
while ( volt_data [ count ] . volt_nominal )
count + + ;
nvalue_table = kzalloc ( sizeof ( struct omap_sr_nvalue_table ) * count ,
GFP_KERNEL ) ;
2012-04-25 09:49:44 +04:00
if ( ! nvalue_table ) {
pr_err ( " OMAP: SmartReflex: cannot allocate memory for n-value table \n " ) ;
return ;
}
for ( i = 0 , j = 0 ; i < count ; i + + ) {
2010-08-18 10:53:12 +04:00
u32 v ;
2012-04-25 09:49:44 +04:00
2010-08-18 10:53:12 +04:00
/*
* In OMAP4 the efuse registers are 24 bit aligned .
2014-04-15 21:37:46 +04:00
* A readl_relaxed will fail for non - 32 bit aligned address
2010-08-18 10:53:12 +04:00
* and hence the 8 - bit read and shift .
*/
if ( cpu_is_omap44xx ( ) ) {
u16 offset = volt_data [ i ] . sr_efuse_offs ;
v = omap_ctrl_readb ( offset ) |
omap_ctrl_readb ( offset + 1 ) < < 8 |
omap_ctrl_readb ( offset + 2 ) < < 16 ;
} else {
2012-04-25 09:49:44 +04:00
v = omap_ctrl_readl ( volt_data [ i ] . sr_efuse_offs ) ;
2010-08-18 10:53:12 +04:00
}
2010-05-29 20:32:23 +04:00
2012-04-25 09:49:44 +04:00
/*
* Many OMAP SoCs don ' t have the eFuse values set .
* For example , pretty much all OMAP3xxx before
* ES3 . something .
*
* XXX There needs to be some way for board files or
* userspace to add these in .
*/
if ( v = = 0 )
continue ;
nvalue_table [ j ] . nvalue = v ;
nvalue_table [ j ] . efuse_offs = volt_data [ i ] . sr_efuse_offs ;
nvalue_table [ j ] . errminlimit = volt_data [ i ] . sr_errminlimit ;
nvalue_table [ j ] . volt_nominal = volt_data [ i ] . volt_nominal ;
j + + ;
2010-05-29 20:32:23 +04:00
}
sr_data - > nvalue_table = nvalue_table ;
2012-04-25 09:49:44 +04:00
sr_data - > nvalue_count = j ;
2010-05-29 20:32:23 +04:00
}
2012-02-20 21:43:30 +04:00
static int __init sr_dev_init ( struct omap_hwmod * oh , void * user )
2010-05-29 20:32:23 +04:00
{
struct omap_sr_data * sr_data ;
2011-07-22 00:48:45 +04:00
struct platform_device * pdev ;
2010-05-29 20:32:23 +04:00
struct omap_volt_data * volt_data ;
2012-03-01 02:33:37 +04:00
struct omap_smartreflex_dev_attr * sr_dev_attr ;
2010-05-29 20:32:23 +04:00
char * name = " smartreflex " ;
static int i ;
sr_data = kzalloc ( sizeof ( struct omap_sr_data ) , GFP_KERNEL ) ;
if ( ! sr_data ) {
2012-07-26 10:54:26 +04:00
pr_err ( " %s: Unable to allocate memory for %s sr_data \n " ,
__func__ , oh - > name ) ;
2010-05-29 20:32:23 +04:00
return - ENOMEM ;
}
2012-03-01 02:33:37 +04:00
sr_dev_attr = ( struct omap_smartreflex_dev_attr * ) oh - > dev_attr ;
if ( ! sr_dev_attr | | ! sr_dev_attr - > sensor_voltdm_name ) {
2012-07-26 10:54:26 +04:00
pr_err ( " %s: No voltage domain specified for %s. Cannot initialize \n " ,
__func__ , oh - > name ) ;
2010-05-29 20:32:23 +04:00
goto exit ;
}
2012-04-24 09:11:27 +04:00
sr_data - > name = oh - > name ;
2010-05-29 20:32:23 +04:00
sr_data - > ip_type = oh - > class - > rev ;
sr_data - > senn_mod = 0x1 ;
sr_data - > senp_mod = 0x1 ;
2012-10-04 20:47:11 +04:00
if ( cpu_is_omap34xx ( ) | | cpu_is_omap44xx ( ) ) {
sr_data - > err_weight = OMAP3430_SR_ERRWEIGHT ;
sr_data - > err_maxlimit = OMAP3430_SR_ERRMAXLIMIT ;
sr_data - > accum_data = OMAP3430_SR_ACCUMDATA ;
if ( ! ( strcmp ( sr_data - > name , " smartreflex_mpu " ) ) ) {
sr_data - > senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT ;
sr_data - > senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT ;
} else {
sr_data - > senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT ;
sr_data - > senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT ;
}
}
2012-03-01 02:33:37 +04:00
sr_data - > voltdm = voltdm_lookup ( sr_dev_attr - > sensor_voltdm_name ) ;
2012-09-27 09:54:22 +04:00
if ( ! sr_data - > voltdm ) {
2010-05-29 20:32:23 +04:00
pr_err ( " %s: Unable to get voltage domain pointer for VDD %s \n " ,
2012-03-01 02:33:37 +04:00
__func__ , sr_dev_attr - > sensor_voltdm_name ) ;
2010-05-29 20:32:23 +04:00
goto exit ;
}
omap_voltage_get_volttable ( sr_data - > voltdm , & volt_data ) ;
if ( ! volt_data ) {
2012-07-26 10:54:26 +04:00
pr_err ( " %s: No Voltage table registered for VDD%d \n " ,
__func__ , i + 1 ) ;
2010-05-29 20:32:23 +04:00
goto exit ;
}
sr_set_nvalues ( volt_data , sr_data ) ;
sr_data - > enable_on_init = sr_enable_on_init ;
2013-02-12 07:58:35 +04:00
pdev = omap_device_build ( name , i , oh , sr_data , sizeof ( * sr_data ) ) ;
2011-07-22 00:48:45 +04:00
if ( IS_ERR ( pdev ) )
2014-09-13 22:31:16 +04:00
pr_warn ( " %s: Could not build omap_device for %s: %s \n " ,
2010-05-29 20:32:23 +04:00
__func__ , name , oh - > name ) ;
exit :
i + + ;
kfree ( sr_data ) ;
return 0 ;
}
/*
* API to be called from board files to enable smartreflex
* autocompensation at init .
*/
void __init omap_enable_smartreflex_on_init ( void )
{
sr_enable_on_init = true ;
}
int __init omap_devinit_smartreflex ( void )
{
return omap_hwmod_for_each_by_class ( " smartreflex " , sr_dev_init , NULL ) ;
}