2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
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 >
*/
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
/* 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 + + ;
2017-06-03 20:09:07 +03:00
nvalue_table = kcalloc ( count , sizeof ( * nvalue_table ) , GFP_KERNEL ) ;
2017-06-03 20:16:27 +03:00
if ( ! nvalue_table )
2012-04-25 09:49:44 +04:00
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
}
2018-02-23 00:57:30 +03:00
extern struct omap_sr_data omap_sr_pdata [ ] ;
2021-02-10 11:53:48 +03:00
static int __init sr_init_by_name ( const char * name , const char * voltdm )
2010-05-29 20:32:23 +04:00
{
2018-02-23 01:05:31 +03:00
struct omap_sr_data * sr_data = NULL ;
2010-05-29 20:32:23 +04:00
struct omap_volt_data * volt_data ;
static int i ;
2021-02-10 11:53:48 +03:00
if ( ! strncmp ( name , " smartreflex_mpu_iva " , 20 ) | |
! strncmp ( name , " smartreflex_mpu " , 16 ) )
2018-02-23 01:05:31 +03:00
sr_data = & omap_sr_pdata [ OMAP_SR_MPU ] ;
2021-02-10 11:53:48 +03:00
else if ( ! strncmp ( name , " smartreflex_core " , 17 ) )
2018-02-23 01:05:31 +03:00
sr_data = & omap_sr_pdata [ OMAP_SR_CORE ] ;
2021-02-10 11:53:48 +03:00
else if ( ! strncmp ( name , " smartreflex_iva " , 16 ) )
2018-02-23 01:05:31 +03:00
sr_data = & omap_sr_pdata [ OMAP_SR_IVA ] ;
if ( ! sr_data ) {
2021-02-10 11:53:48 +03:00
pr_err ( " %s: Unknown instance %s \n " , __func__ , name ) ;
2018-02-23 01:05:31 +03:00
return - EINVAL ;
}
2010-05-29 20:32:23 +04:00
2021-02-10 11:53:48 +03:00
sr_data - > name = name ;
2019-03-21 21:00:21 +03:00
if ( cpu_is_omap343x ( ) )
sr_data - > ip_type = 1 ;
else
sr_data - > ip_type = 2 ;
2010-05-29 20:32:23 +04:00
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 ;
}
}
2021-02-10 11:53:48 +03:00
sr_data - > voltdm = voltdm_lookup ( voltdm ) ;
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 " ,
2021-02-10 11:53:48 +03:00
__func__ , voltdm ) ;
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 ) ;
exit :
i + + ;
2018-02-23 01:05:31 +03:00
2010-05-29 20:32:23 +04:00
return 0 ;
}
2021-03-12 11:11:24 +03:00
# ifdef CONFIG_OMAP_HWMOD
2021-02-10 11:53:48 +03:00
static int __init sr_dev_init ( struct omap_hwmod * oh , void * user )
{
struct omap_smartreflex_dev_attr * sr_dev_attr ;
sr_dev_attr = ( struct omap_smartreflex_dev_attr * ) oh - > dev_attr ;
if ( ! sr_dev_attr | | ! sr_dev_attr - > sensor_voltdm_name ) {
pr_err ( " %s: No voltage domain specified for %s. Cannot initialize \n " ,
__func__ , oh - > name ) ;
return 0 ;
}
return sr_init_by_name ( oh - > name , sr_dev_attr - > sensor_voltdm_name ) ;
}
2021-03-12 11:11:24 +03:00
# else
static int __init sr_dev_init ( struct omap_hwmod * oh , void * user )
{
return - EINVAL ;
}
# endif
2021-02-10 11:53:48 +03:00
static const char * const omap4_sr_instances [ ] = {
" mpu " ,
" iva " ,
" core " ,
} ;
static const char * const dra7_sr_instances [ ] = {
" mpu " ,
" core " ,
} ;
2010-05-29 20:32:23 +04:00
int __init omap_devinit_smartreflex ( void )
{
2021-03-31 09:27:41 +03:00
const char * const * sr_inst = NULL ;
2021-02-10 11:53:48 +03:00
int i , nr_sr = 0 ;
if ( soc_is_omap44xx ( ) ) {
sr_inst = omap4_sr_instances ;
nr_sr = ARRAY_SIZE ( omap4_sr_instances ) ;
} else if ( soc_is_dra7xx ( ) ) {
sr_inst = dra7_sr_instances ;
nr_sr = ARRAY_SIZE ( dra7_sr_instances ) ;
}
if ( nr_sr ) {
const char * name , * voltdm ;
for ( i = 0 ; i < nr_sr ; i + + ) {
name = kasprintf ( GFP_KERNEL , " smartreflex_%s " , sr_inst [ i ] ) ;
voltdm = sr_inst [ i ] ;
sr_init_by_name ( name , voltdm ) ;
}
return 0 ;
}
2010-05-29 20:32:23 +04:00
return omap_hwmod_for_each_by_class ( " smartreflex " , sr_dev_init , NULL ) ;
}