2011-03-21 14:29:13 -07:00
# include <linux/kernel.h>
# include <linux/init.h>
2011-11-10 22:45:17 +01:00
# include "common.h"
2011-03-21 14:29:13 -07:00
# include "voltage.h"
# include "vp.h"
# include "prm-regbits-34xx.h"
# include "prm-regbits-44xx.h"
# include "prm44xx.h"
2011-07-15 17:05:48 -07:00
static u32 _vp_set_init_voltage ( struct voltagedomain * voltdm , u32 volt )
2011-03-21 14:29:13 -07:00
{
2011-04-04 15:25:07 -07:00
struct omap_vp_instance * vp = voltdm - > vp ;
2011-03-21 14:29:13 -07:00
u32 vpconfig ;
char vsel ;
2011-07-15 17:05:48 -07:00
vsel = voltdm - > pmic - > uv_to_vsel ( volt ) ;
2011-03-21 14:29:13 -07:00
2011-03-28 10:40:15 -07:00
vpconfig = voltdm - > read ( vp - > vpconfig ) ;
2011-04-04 15:25:07 -07:00
vpconfig & = ~ ( vp - > common - > vpconfig_initvoltage_mask |
2011-07-15 17:05:48 -07:00
vp - > common - > vpconfig_forceupdate |
vp - > common - > vpconfig_initvdd ) ;
2011-04-04 16:02:28 -07:00
vpconfig | = vsel < < __ffs ( vp - > common - > vpconfig_initvoltage_mask ) ;
2011-03-28 10:40:15 -07:00
voltdm - > write ( vpconfig , vp - > vpconfig ) ;
2011-03-21 14:29:13 -07:00
/* Trigger initVDD value copy to voltage processor */
2011-04-04 15:25:07 -07:00
voltdm - > write ( ( vpconfig | vp - > common - > vpconfig_initvdd ) ,
2011-03-28 10:40:15 -07:00
vp - > vpconfig ) ;
2011-03-21 14:29:13 -07:00
/* Clear initVDD copy trigger bit */
2011-03-28 10:40:15 -07:00
voltdm - > write ( vpconfig , vp - > vpconfig ) ;
2011-07-15 17:05:48 -07:00
return vpconfig ;
2011-03-21 14:29:13 -07:00
}
/* Generic voltage init functions */
void __init omap_vp_init ( struct voltagedomain * voltdm )
{
2011-04-04 15:25:07 -07:00
struct omap_vp_instance * vp = voltdm - > vp ;
2011-04-04 17:58:21 -07:00
u32 val , sys_clk_rate , timeout , waittime ;
u32 vddmin , vddmax , vstepmin , vstepmax ;
2011-03-21 14:29:13 -07:00
2012-02-07 09:42:11 +00:00
if ( ! voltdm - > pmic | | ! voltdm - > pmic - > uv_to_vsel ) {
pr_err ( " %s: No PMIC info for vdd_%s \n " , __func__ , voltdm - > name ) ;
return ;
}
2011-03-28 10:40:15 -07:00
if ( ! voltdm - > read | | ! voltdm - > write ) {
2011-03-21 14:29:13 -07:00
pr_err ( " %s: No read/write API for accessing vdd_%s regs \n " ,
__func__ , voltdm - > name ) ;
return ;
}
2011-07-14 11:10:27 -07:00
vp - > enabled = false ;
/* Divide to avoid overflow */
sys_clk_rate = voltdm - > sys_clk . rate / 1000 ;
2011-04-04 17:58:21 -07:00
timeout = ( sys_clk_rate * voltdm - > pmic - > vp_timeout_us ) / 1000 ;
2012-09-25 19:33:40 +03:00
vddmin = max ( voltdm - > vp_param - > vddmin , voltdm - > pmic - > vddmin ) ;
vddmax = min ( voltdm - > vp_param - > vddmax , voltdm - > pmic - > vddmax ) ;
vddmin = voltdm - > pmic - > uv_to_vsel ( vddmin ) ;
vddmax = voltdm - > pmic - > uv_to_vsel ( vddmax ) ;
2011-07-14 11:10:27 -07:00
2012-03-06 12:51:12 -06:00
waittime = DIV_ROUND_UP ( voltdm - > pmic - > step_size * sys_clk_rate ,
1000 * voltdm - > pmic - > slew_rate ) ;
2011-04-04 17:58:21 -07:00
vstepmin = voltdm - > pmic - > vp_vstepmin ;
vstepmax = voltdm - > pmic - > vp_vstepmax ;
/*
* VP_CONFIG : error gain is not set here , it will be updated
* on each scale , based on OPP .
*/
val = ( voltdm - > pmic - > vp_erroroffset < <
__ffs ( voltdm - > vp - > common - > vpconfig_erroroffset_mask ) ) |
2011-04-04 15:25:07 -07:00
vp - > common - > vpconfig_timeouten ;
2011-04-04 17:58:21 -07:00
voltdm - > write ( val , vp - > vpconfig ) ;
/* VSTEPMIN */
val = ( waittime < < vp - > common - > vstepmin_smpswaittimemin_shift ) |
( vstepmin < < vp - > common - > vstepmin_stepmin_shift ) ;
voltdm - > write ( val , vp - > vstepmin ) ;
/* VSTEPMAX */
val = ( vstepmax < < vp - > common - > vstepmax_stepmax_shift ) |
( waittime < < vp - > common - > vstepmax_smpswaittimemax_shift ) ;
voltdm - > write ( val , vp - > vstepmax ) ;
/* VLIMITTO */
val = ( vddmax < < vp - > common - > vlimitto_vddmax_shift ) |
( vddmin < < vp - > common - > vlimitto_vddmin_shift ) |
( timeout < < vp - > common - > vlimitto_timeout_shift ) ;
voltdm - > write ( val , vp - > vlimitto ) ;
2011-03-21 14:29:13 -07:00
}
2011-04-05 15:15:31 -07:00
int omap_vp_update_errorgain ( struct voltagedomain * voltdm ,
unsigned long target_volt )
{
struct omap_volt_data * volt_data ;
2011-07-18 15:31:43 -07:00
if ( ! voltdm - > vp )
return - EINVAL ;
2011-04-05 15:15:31 -07:00
/* Get volt_data corresponding to target_volt */
volt_data = omap_voltage_get_voltdata ( voltdm , target_volt ) ;
if ( IS_ERR ( volt_data ) )
return - EINVAL ;
/* Setting vp errorgain based on the voltage */
voltdm - > rmw ( voltdm - > vp - > common - > vpconfig_errorgain_mask ,
volt_data - > vp_errgain < <
__ffs ( voltdm - > vp - > common - > vpconfig_errorgain_mask ) ,
voltdm - > vp - > vpconfig ) ;
return 0 ;
}
2011-03-21 14:29:13 -07:00
/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale ( struct voltagedomain * voltdm ,
unsigned long target_volt )
{
2011-04-04 15:25:07 -07:00
struct omap_vp_instance * vp = voltdm - > vp ;
2011-03-21 14:29:13 -07:00
u32 vpconfig ;
u8 target_vsel , current_vsel ;
int ret , timeout = 0 ;
ret = omap_vc_pre_scale ( voltdm , target_volt , & target_vsel , & current_vsel ) ;
if ( ret )
return ret ;
/*
* Clear all pending TransactionDone interrupt / status . Typical latency
* is < 3u s
*/
while ( timeout + + < VP_TRANXDONE_TIMEOUT ) {
2011-04-04 15:25:07 -07:00
vp - > common - > ops - > clear_txdone ( vp - > id ) ;
if ( ! vp - > common - > ops - > check_txdone ( vp - > id ) )
2011-03-21 14:29:13 -07:00
break ;
udelay ( 1 ) ;
}
if ( timeout > = VP_TRANXDONE_TIMEOUT ) {
2012-10-25 13:37:16 -05:00
pr_warn ( " %s: vdd_%s TRANXDONE timeout exceeded. Voltage change aborted \n " ,
2012-07-26 00:54:26 -06:00
__func__ , voltdm - > name ) ;
2011-03-21 14:29:13 -07:00
return - ETIMEDOUT ;
}
2011-07-15 17:05:48 -07:00
vpconfig = _vp_set_init_voltage ( voltdm , target_volt ) ;
2011-03-21 14:29:13 -07:00
/* Force update of voltage */
2011-07-15 17:05:48 -07:00
voltdm - > write ( vpconfig | vp - > common - > vpconfig_forceupdate ,
voltdm - > vp - > vpconfig ) ;
2011-03-21 14:29:13 -07:00
/*
* Wait for TransactionDone . Typical latency is < 200u s .
* Depends on SMPSWAITTIMEMIN / MAX and voltage change
*/
timeout = 0 ;
2011-04-04 15:25:07 -07:00
omap_test_timeout ( vp - > common - > ops - > check_txdone ( vp - > id ) ,
2011-03-21 14:29:13 -07:00
VP_TRANXDONE_TIMEOUT , timeout ) ;
if ( timeout > = VP_TRANXDONE_TIMEOUT )
2012-07-26 00:54:26 -06:00
pr_err ( " %s: vdd_%s TRANXDONE timeout exceeded. TRANXDONE never got set after the voltage update \n " ,
__func__ , voltdm - > name ) ;
2011-03-21 14:29:13 -07:00
omap_vc_post_scale ( voltdm , target_volt , target_vsel , current_vsel ) ;
/*
* Disable TransactionDone interrupt , clear all status , clear
* control registers
*/
timeout = 0 ;
while ( timeout + + < VP_TRANXDONE_TIMEOUT ) {
2011-04-04 15:25:07 -07:00
vp - > common - > ops - > clear_txdone ( vp - > id ) ;
if ( ! vp - > common - > ops - > check_txdone ( vp - > id ) )
2011-03-21 14:29:13 -07:00
break ;
udelay ( 1 ) ;
}
if ( timeout > = VP_TRANXDONE_TIMEOUT )
2012-07-26 00:54:26 -06:00
pr_warn ( " %s: vdd_%s TRANXDONE timeout exceeded while trying to clear the TRANXDONE status \n " ,
2011-03-21 14:29:13 -07:00
__func__ , voltdm - > name ) ;
/* Clear force bit */
2011-03-28 10:40:15 -07:00
voltdm - > write ( vpconfig , vp - > vpconfig ) ;
2011-03-21 14:29:13 -07:00
return 0 ;
}
/**
* omap_vp_enable ( ) - API to enable a particular VP
* @ voltdm : pointer to the VDD whose VP is to be enabled .
*
* This API enables a particular voltage processor . Needed by the smartreflex
* class drivers .
*/
void omap_vp_enable ( struct voltagedomain * voltdm )
{
2011-04-04 15:25:07 -07:00
struct omap_vp_instance * vp ;
2011-07-15 17:05:48 -07:00
u32 vpconfig , volt ;
2011-03-21 14:29:13 -07:00
if ( ! voltdm | | IS_ERR ( voltdm ) ) {
2012-10-25 13:37:16 -05:00
pr_warn ( " %s: VDD specified does not exist! \n " , __func__ ) ;
2011-03-21 14:29:13 -07:00
return ;
}
2011-04-04 15:25:07 -07:00
vp = voltdm - > vp ;
2011-03-28 10:40:15 -07:00
if ( ! voltdm - > read | | ! voltdm - > write ) {
2011-03-21 14:29:13 -07:00
pr_err ( " %s: No read/write API for accessing vdd_%s regs \n " ,
__func__ , voltdm - > name ) ;
return ;
}
/* If VP is already enabled, do nothing. Return */
2011-04-04 15:25:07 -07:00
if ( vp - > enabled )
2011-03-21 14:29:13 -07:00
return ;
2011-07-15 17:05:48 -07:00
volt = voltdm_get_voltage ( voltdm ) ;
if ( ! volt ) {
2012-10-25 13:37:16 -05:00
pr_warn ( " %s: unable to find current voltage for %s \n " ,
__func__ , voltdm - > name ) ;
2011-07-15 17:05:48 -07:00
return ;
}
vpconfig = _vp_set_init_voltage ( voltdm , volt ) ;
2011-03-21 14:29:13 -07:00
/* Enable VP */
2011-04-04 15:25:07 -07:00
vpconfig | = vp - > common - > vpconfig_vpenable ;
2011-03-28 10:40:15 -07:00
voltdm - > write ( vpconfig , vp - > vpconfig ) ;
2011-07-15 17:05:48 -07:00
2011-04-04 15:25:07 -07:00
vp - > enabled = true ;
2011-03-21 14:29:13 -07:00
}
/**
* omap_vp_disable ( ) - API to disable a particular VP
* @ voltdm : pointer to the VDD whose VP is to be disabled .
*
* This API disables a particular voltage processor . Needed by the smartreflex
* class drivers .
*/
void omap_vp_disable ( struct voltagedomain * voltdm )
{
2011-04-04 15:25:07 -07:00
struct omap_vp_instance * vp ;
2011-03-21 14:29:13 -07:00
u32 vpconfig ;
int timeout ;
if ( ! voltdm | | IS_ERR ( voltdm ) ) {
2012-10-25 13:37:16 -05:00
pr_warn ( " %s: VDD specified does not exist! \n " , __func__ ) ;
2011-03-21 14:29:13 -07:00
return ;
}
2011-04-04 15:25:07 -07:00
vp = voltdm - > vp ;
2011-03-28 10:40:15 -07:00
if ( ! voltdm - > read | | ! voltdm - > write ) {
2011-03-21 14:29:13 -07:00
pr_err ( " %s: No read/write API for accessing vdd_%s regs \n " ,
__func__ , voltdm - > name ) ;
return ;
}
/* If VP is already disabled, do nothing. Return */
2011-04-04 15:25:07 -07:00
if ( ! vp - > enabled ) {
2012-07-26 00:54:26 -06:00
pr_warn ( " %s: Trying to disable VP for vdd_%s when it is already disabled \n " ,
__func__ , voltdm - > name ) ;
2011-03-21 14:29:13 -07:00
return ;
}
/* Disable VP */
2011-03-28 10:40:15 -07:00
vpconfig = voltdm - > read ( vp - > vpconfig ) ;
2011-04-04 15:25:07 -07:00
vpconfig & = ~ vp - > common - > vpconfig_vpenable ;
2011-03-28 10:40:15 -07:00
voltdm - > write ( vpconfig , vp - > vpconfig ) ;
2011-03-21 14:29:13 -07:00
/*
* Wait for VP idle Typical latency is < 2u s . Maximum latency is ~ 100u s
*/
2011-03-28 10:40:15 -07:00
omap_test_timeout ( ( voltdm - > read ( vp - > vstatus ) ) ,
VP_IDLE_TIMEOUT , timeout ) ;
2011-03-21 14:29:13 -07:00
if ( timeout > = VP_IDLE_TIMEOUT )
2012-10-25 13:37:16 -05:00
pr_warn ( " %s: vdd_%s idle timedout \n " , __func__ , voltdm - > name ) ;
2011-03-21 14:29:13 -07:00
2011-04-04 15:25:07 -07:00
vp - > enabled = false ;
2011-03-21 14:29:13 -07:00
return ;
}