2010-05-29 22:02:23 +05:30
/*
* 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 16:06:20 +05:30
# include <linux/power/smartreflex.h>
2010-05-29 22:02:23 +05:30
# include <linux/err.h>
# include <linux/slab.h>
2010-08-18 12:23:12 +05:30
# include <linux/io.h>
2010-05-29 22:02:23 +05:30
2012-10-05 13:25:59 -07:00
# include "soc.h"
2012-10-02 17:25:48 -07:00
# include "omap_device.h"
2011-02-25 15:54:33 -07:00
# include "voltage.h"
2010-05-29 22:02:23 +05:30
# include "control.h"
2011-01-03 13:35:41 -06:00
# include "pm.h"
2010-05-29 22:02:23 +05:30
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 11:19:44 +05:30
int i , j , count = 0 ;
sr_data - > nvalue_count = 0 ;
sr_data - > nvalue_table = NULL ;
2010-05-29 22:02:23 +05:30
while ( volt_data [ count ] . volt_nominal )
count + + ;
2017-06-03 19:09:07 +02:00
nvalue_table = kcalloc ( count , sizeof ( * nvalue_table ) , GFP_KERNEL ) ;
2017-06-03 19:16:27 +02:00
if ( ! nvalue_table )
2012-04-25 11:19:44 +05:30
return ;
for ( i = 0 , j = 0 ; i < count ; i + + ) {
2010-08-18 12:23:12 +05:30
u32 v ;
2012-04-25 11:19:44 +05:30
2010-08-18 12:23:12 +05:30
/*
* In OMAP4 the efuse registers are 24 bit aligned .
2014-04-15 20:37:46 +03:00
* A readl_relaxed will fail for non - 32 bit aligned address
2010-08-18 12:23:12 +05:30
* 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 11:19:44 +05:30
v = omap_ctrl_readl ( volt_data [ i ] . sr_efuse_offs ) ;
2010-08-18 12:23:12 +05:30
}
2010-05-29 22:02:23 +05:30
2012-04-25 11:19:44 +05:30
/*
* 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 22:02:23 +05:30
}
sr_data - > nvalue_table = nvalue_table ;
2012-04-25 11:19:44 +05:30
sr_data - > nvalue_count = j ;
2010-05-29 22:02:23 +05:30
}
2012-02-20 09:43:30 -08:00
static int __init sr_dev_init ( struct omap_hwmod * oh , void * user )
2010-05-29 22:02:23 +05:30
{
struct omap_sr_data * sr_data ;
2011-07-21 13:48:45 -07:00
struct platform_device * pdev ;
2010-05-29 22:02:23 +05:30
struct omap_volt_data * volt_data ;
2012-02-29 23:33:37 +01:00
struct omap_smartreflex_dev_attr * sr_dev_attr ;
2010-05-29 22:02:23 +05:30
char * name = " smartreflex " ;
static int i ;
2017-06-03 19:02:24 +02:00
sr_data = kzalloc ( sizeof ( * sr_data ) , GFP_KERNEL ) ;
2017-06-03 19:16:27 +02:00
if ( ! sr_data )
2010-05-29 22:02:23 +05:30
return - ENOMEM ;
2012-02-29 23:33:37 +01: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 00:54:26 -06:00
pr_err ( " %s: No voltage domain specified for %s. Cannot initialize \n " ,
__func__ , oh - > name ) ;
2010-05-29 22:02:23 +05:30
goto exit ;
}
2012-04-24 10:41:27 +05:30
sr_data - > name = oh - > name ;
2010-05-29 22:02:23 +05:30
sr_data - > ip_type = oh - > class - > rev ;
sr_data - > senn_mod = 0x1 ;
sr_data - > senp_mod = 0x1 ;
2012-10-04 18:47:11 +02: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-02-29 23:33:37 +01:00
sr_data - > voltdm = voltdm_lookup ( sr_dev_attr - > sensor_voltdm_name ) ;
2012-09-27 13:54:22 +08:00
if ( ! sr_data - > voltdm ) {
2010-05-29 22:02:23 +05:30
pr_err ( " %s: Unable to get voltage domain pointer for VDD %s \n " ,
2012-02-29 23:33:37 +01:00
__func__ , sr_dev_attr - > sensor_voltdm_name ) ;
2010-05-29 22:02:23 +05:30
goto exit ;
}
omap_voltage_get_volttable ( sr_data - > voltdm , & volt_data ) ;
if ( ! volt_data ) {
2012-07-26 00:54:26 -06:00
pr_err ( " %s: No Voltage table registered for VDD%d \n " ,
__func__ , i + 1 ) ;
2010-05-29 22:02:23 +05:30
goto exit ;
}
sr_set_nvalues ( volt_data , sr_data ) ;
sr_data - > enable_on_init = sr_enable_on_init ;
2013-02-12 03:58:35 +00:00
pdev = omap_device_build ( name , i , oh , sr_data , sizeof ( * sr_data ) ) ;
2011-07-21 13:48:45 -07:00
if ( IS_ERR ( pdev ) )
2014-09-13 11:31:16 -07:00
pr_warn ( " %s: Could not build omap_device for %s: %s \n " ,
2010-05-29 22:02:23 +05:30
__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 ) ;
}