2018-05-01 06:15:48 +01:00
/*
2018-08-05 12:40:32 +01:00
* Copyright ( c ) 2018 naehrwert
2021-01-04 00:34:58 +00:00
* Copyright ( c ) 2019 - 2020 CTCaer
2018-08-05 12:40:32 +01:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2018-05-01 06:15:48 +01:00
2020-06-14 14:45:45 +01:00
# include <power/max7762x.h>
# include <power/max77620.h>
2021-01-04 00:34:58 +00:00
# include <power/max77812.h>
# include <soc/fuse.h>
2020-06-14 14:45:45 +01:00
# include <soc/i2c.h>
2022-06-27 08:22:19 +01:00
# include <soc/timer.h>
2021-01-04 00:34:58 +00:00
# include <soc/t210.h>
2018-05-01 06:15:48 +01:00
2021-01-04 00:34:58 +00:00
# define REGULATOR_SD 0
2018-05-01 06:15:48 +01:00
# define REGULATOR_LDO 1
2021-01-04 00:34:58 +00:00
# define REGULATOR_BC0 2
# define REGULATOR_BC1 3
typedef struct _max77620_fps_t
{
u8 fps_addr ;
u8 fps_src ;
u8 pd_period ;
u8 pu_period ;
} max77620_fps_t ;
typedef struct _max77621_ctrl_t
{
u8 ctrl1_por ;
u8 ctrl1_hos ;
u8 ctrl2_por ;
u8 ctrl2_hos ;
} max77621_ctrl_t ;
typedef struct _max77812_ctrl_t
{
u8 mask ;
u8 shift ;
u8 rsvd0 ;
u8 rsvd1 ;
} max77812_en_t ;
2018-05-01 06:15:48 +01:00
typedef struct _max77620_regulator_t
{
const char * name ;
2019-02-15 23:23:14 +00:00
2021-01-04 00:34:58 +00:00
u32 uv_step ;
u32 uv_min ;
u32 uv_default ;
u32 uv_max ;
2019-02-15 23:23:14 +00:00
2021-01-04 00:34:58 +00:00
u8 type ;
2018-05-01 06:15:48 +01:00
u8 volt_addr ;
u8 cfg_addr ;
u8 volt_mask ;
2021-01-04 00:34:58 +00:00
union {
max77620_fps_t fps ;
max77621_ctrl_t ctrl ;
max77812_en_t enable ;
} ;
2018-05-01 06:15:48 +01:00
} max77620_regulator_t ;
static const max77620_regulator_t _pmic_regulators [ ] = {
2021-01-04 00:34:58 +00:00
{ " sd0 " , 12500 , 600000 , 625000 , 1400000 , REGULATOR_SD , MAX77620_REG_SD0 , MAX77620_REG_SD0_CFG , MAX77620_SD0_VOLT_MASK , { { MAX77620_REG_FPS_SD0 , 1 , 7 , 1 } } } ,
2021-04-11 08:20:54 +01:00
{ " sd1 " , 12500 , 600000 , 1125000 , 1250000 , REGULATOR_SD , MAX77620_REG_SD1 , MAX77620_REG_SD1_CFG , MAX77620_SD1_VOLT_MASK , { { MAX77620_REG_FPS_SD1 , 0 , 1 , 5 } } } ,
2021-01-04 00:34:58 +00:00
{ " sd2 " , 12500 , 600000 , 1325000 , 1350000 , REGULATOR_SD , MAX77620_REG_SD2 , MAX77620_REG_SD2_CFG , MAX77620_SDX_VOLT_MASK , { { MAX77620_REG_FPS_SD2 , 1 , 5 , 2 } } } ,
{ " sd3 " , 12500 , 600000 , 1800000 , 1800000 , REGULATOR_SD , MAX77620_REG_SD3 , MAX77620_REG_SD3_CFG , MAX77620_SDX_VOLT_MASK , { { MAX77620_REG_FPS_SD3 , 0 , 3 , 3 } } } ,
{ " ldo0 " , 25000 , 800000 , 1200000 , 1200000 , REGULATOR_LDO , MAX77620_REG_LDO0_CFG , MAX77620_REG_LDO0_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO0 , 3 , 7 , 0 } } } ,
{ " ldo1 " , 25000 , 800000 , 1050000 , 1050000 , REGULATOR_LDO , MAX77620_REG_LDO1_CFG , MAX77620_REG_LDO1_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO1 , 3 , 7 , 0 } } } ,
{ " ldo2 " , 50000 , 800000 , 1800000 , 3300000 , REGULATOR_LDO , MAX77620_REG_LDO2_CFG , MAX77620_REG_LDO2_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO2 , 3 , 7 , 0 } } } ,
{ " ldo3 " , 50000 , 800000 , 3100000 , 3100000 , REGULATOR_LDO , MAX77620_REG_LDO3_CFG , MAX77620_REG_LDO3_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO3 , 3 , 7 , 0 } } } ,
{ " ldo4 " , 12500 , 800000 , 850000 , 1000000 , REGULATOR_LDO , MAX77620_REG_LDO4_CFG , MAX77620_REG_LDO4_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO4 , 0 , 7 , 1 } } } ,
{ " ldo5 " , 50000 , 800000 , 1800000 , 1800000 , REGULATOR_LDO , MAX77620_REG_LDO5_CFG , MAX77620_REG_LDO5_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO5 , 3 , 7 , 0 } } } ,
{ " ldo6 " , 50000 , 800000 , 2900000 , 2900000 , REGULATOR_LDO , MAX77620_REG_LDO6_CFG , MAX77620_REG_LDO6_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO6 , 3 , 7 , 0 } } } ,
{ " ldo7 " , 50000 , 800000 , 1050000 , 1050000 , REGULATOR_LDO , MAX77620_REG_LDO7_CFG , MAX77620_REG_LDO7_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO7 , 1 , 4 , 3 } } } ,
{ " ldo8 " , 50000 , 800000 , 1050000 , 2800000 , REGULATOR_LDO , MAX77620_REG_LDO8_CFG , MAX77620_REG_LDO8_CFG2 , MAX77620_LDO_VOLT_MASK , { { MAX77620_REG_FPS_LDO8 , 3 , 7 , 0 } } } ,
2022-10-11 01:53:17 +01:00
{ " max77621_CPU " , 6250 , 606250 , 1000000 , 1400000 , REGULATOR_BC0 , MAX77621_REG_VOUT , MAX77621_REG_VOUT_DVS , MAX77621_DVC_DVS_VOLT_MASK , { { MAX77621_CPU_CTRL1_POR_DEFAULT , MAX77621_CPU_CTRL1_HOS_DEFAULT , MAX77621_CPU_CTRL2_POR_DEFAULT , MAX77621_CPU_CTRL2_HOS_DEFAULT } } } ,
{ " max77621_GPU " , 6250 , 606250 , 1200000 , 1400000 , REGULATOR_BC0 , MAX77621_REG_VOUT , MAX77621_REG_VOUT_DVS , MAX77621_DVC_DVS_VOLT_MASK , { { MAX77621_CPU_CTRL1_POR_DEFAULT , MAX77621_CPU_CTRL1_HOS_DEFAULT , MAX77621_CPU_CTRL2_POR_DEFAULT , MAX77621_CPU_CTRL2_HOS_DEFAULT } } } ,
2021-01-04 00:34:58 +00:00
{ " max77812_CPU " , 5000 , 250000 , 600000 , 1525000 , REGULATOR_BC1 , MAX77812_REG_M4_VOUT , MAX77812_REG_EN_CTRL , MAX77812_BUCK_VOLT_MASK , { { MAX77812_EN_CTRL_EN_M4_MASK , MAX77812_EN_CTRL_EN_M4_SHIFT , 0 , 0 } } } ,
2022-10-11 01:53:17 +01:00
{ " max77812_RAM " , 5000 , 250000 , 600000 , 650000 , REGULATOR_BC1 , MAX77812_REG_M3_VOUT , MAX77812_REG_EN_CTRL , MAX77812_BUCK_VOLT_MASK , { { MAX77812_EN_CTRL_EN_M3_MASK , MAX77812_EN_CTRL_EN_M3_SHIFT , 0 , 0 } } } // Only on PHASE211 configuration.
2021-01-04 00:34:58 +00:00
//{ "max77812_GPU", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M1_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M1_MASK, MAX77812_EN_CTRL_EN_M1_SHIFT, 0, 0 }} },
2018-05-01 06:15:48 +01:00
} ;
2021-01-04 00:34:58 +00:00
static u8 _max77812_get_address ( )
{
static u8 max77812_i2c_addr = 0 ;
if ( max77812_i2c_addr )
return max77812_i2c_addr ;
max77812_i2c_addr =
! ( FUSE ( FUSE_RESERVED_ODM28_T210B01 ) & 1 ) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR ;
return max77812_i2c_addr ;
}
static u8 _max7762x_get_i2c_address ( u32 id )
{
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
// Choose the correct i2c address.
switch ( reg - > type )
{
case REGULATOR_SD :
case REGULATOR_LDO :
return MAX77620_I2C_ADDR ;
case REGULATOR_BC0 :
return ( id = = REGULATOR_CPU0 ? MAX77621_CPU_I2C_ADDR : MAX77621_GPU_I2C_ADDR ) ;
case REGULATOR_BC1 :
2022-12-19 03:28:35 +00:00
{
u8 reg_addr = _max77812_get_address ( ) ;
if ( id = = REGULATOR_RAM1 & & reg_addr = = MAX77812_PHASE31_CPU_I2C_ADDR )
reg_addr = 0 ;
return reg_addr ;
}
2021-01-04 00:34:58 +00:00
default :
return 0 ;
}
}
static void _max7762x_set_reg ( u8 addr , u8 reg , u8 val )
2019-12-04 20:02:17 +00:00
{
2020-11-25 23:43:19 +00:00
u32 retries = 100 ;
while ( retries )
2019-12-04 20:02:17 +00:00
{
2021-01-04 00:34:58 +00:00
if ( i2c_send_byte ( I2C_5 , addr , reg , val ) )
2020-11-25 23:43:19 +00:00
break ;
2021-01-04 00:34:58 +00:00
usleep ( 50 ) ;
2020-11-25 23:43:19 +00:00
retries - - ;
}
2019-12-04 20:02:17 +00:00
}
2018-05-01 06:15:48 +01:00
int max77620_regulator_get_status ( u32 id )
{
2021-01-04 00:34:58 +00:00
if ( id > REGULATOR_LDO8 )
2018-05-01 06:15:48 +01:00
return 0 ;
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
2021-01-04 00:34:58 +00:00
// SD power OK status.
2018-05-01 06:15:48 +01:00
if ( reg - > type = = REGULATOR_SD )
2021-01-04 00:34:58 +00:00
{
u8 mask = 1u < < ( 7 - id ) ;
return ( i2c_recv_byte ( I2C_5 , MAX77620_I2C_ADDR , MAX77620_REG_STATSD ) & mask ) ? 0 : 1 ;
}
// LDO power OK status.
return ( i2c_recv_byte ( I2C_5 , MAX77620_I2C_ADDR , reg - > cfg_addr ) & MAX77620_LDO_CFG2_POK_MASK ) ? 1 : 0 ;
2018-05-01 06:15:48 +01:00
}
int max77620_regulator_config_fps ( u32 id )
{
2021-01-04 00:34:58 +00:00
if ( id > REGULATOR_LDO8 )
2018-05-01 06:15:48 +01:00
return 0 ;
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
2021-01-04 00:34:58 +00:00
// Set FPS configuration.
_max7762x_set_reg ( MAX77620_I2C_ADDR ,
reg - > fps . fps_addr ,
( reg - > fps . fps_src < < MAX77620_FPS_SRC_SHIFT ) |
( reg - > fps . pu_period < < MAX77620_FPS_PU_PERIOD_SHIFT ) |
( reg - > fps . pd_period < < MAX77620_FPS_PD_PERIOD_SHIFT ) ) ;
2018-05-01 06:15:48 +01:00
return 1 ;
}
2022-10-11 01:53:17 +01:00
int max7762x_regulator_set_voltage ( u32 id , u32 uv )
2018-05-01 06:15:48 +01:00
{
if ( id > REGULATOR_MAX )
return 0 ;
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
2022-10-11 01:53:17 +01:00
if ( uv < reg - > uv_min | | uv > reg - > uv_max )
2018-05-01 06:15:48 +01:00
return 0 ;
2021-01-04 00:34:58 +00:00
u8 addr = _max7762x_get_i2c_address ( id ) ;
2022-12-19 03:28:35 +00:00
if ( ! addr )
return 0 ;
2021-01-04 00:34:58 +00:00
// Calculate voltage multiplier.
2022-10-11 01:53:17 +01:00
u32 mult = ( uv + reg - > uv_step - 1 - reg - > uv_min ) / reg - > uv_step ;
2021-01-04 00:34:58 +00:00
u8 val = i2c_recv_byte ( I2C_5 , addr , reg - > volt_addr ) ;
2018-05-01 06:15:48 +01:00
val = ( val & ~ reg - > volt_mask ) | ( mult & reg - > volt_mask ) ;
2021-01-04 00:34:58 +00:00
// Set voltage.
_max7762x_set_reg ( addr , reg - > volt_addr , val ) ;
// If max77621 set DVS voltage also.
if ( reg - > type = = REGULATOR_BC0 )
_max7762x_set_reg ( addr , reg - > cfg_addr , MAX77621_VOUT_ENABLE_MASK | val ) ;
// Wait for ramp up/down delay.
2018-07-04 16:39:26 +01:00
usleep ( 1000 ) ;
2018-05-01 06:15:48 +01:00
return 1 ;
}
2021-01-04 00:34:58 +00:00
int max7762x_regulator_enable ( u32 id , bool enable )
2018-05-01 06:15:48 +01:00
{
2021-01-04 00:34:58 +00:00
u8 reg_addr ;
u8 enable_val ;
u8 enable_mask ;
u8 enable_shift ;
2018-05-01 06:15:48 +01:00
if ( id > REGULATOR_MAX )
return 0 ;
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
2021-01-04 00:34:58 +00:00
// Choose the correct i2c and register addresses and mask/shift for each type.
switch ( reg - > type )
{
case REGULATOR_SD :
reg_addr = reg - > cfg_addr ;
enable_val = MAX77620_POWER_MODE_NORMAL ;
enable_mask = MAX77620_SD_POWER_MODE_MASK ;
enable_shift = MAX77620_SD_POWER_MODE_SHIFT ;
break ;
case REGULATOR_LDO :
reg_addr = reg - > volt_addr ;
enable_val = MAX77620_POWER_MODE_NORMAL ;
enable_mask = MAX77620_LDO_POWER_MODE_MASK ;
enable_shift = MAX77620_LDO_POWER_MODE_SHIFT ;
break ;
case REGULATOR_BC0 :
reg_addr = reg - > volt_addr ;
enable_val = MAX77621_VOUT_ENABLE ;
enable_mask = MAX77621_DVC_DVS_ENABLE_MASK ;
enable_shift = MAX77621_DVC_DVS_ENABLE_SHIFT ;
break ;
case REGULATOR_BC1 :
reg_addr = reg - > cfg_addr ;
enable_val = MAX77812_EN_CTRL_ENABLE ;
enable_mask = reg - > enable . mask ;
enable_shift = reg - > enable . shift ;
break ;
default :
return 0 ;
}
u8 addr = _max7762x_get_i2c_address ( id ) ;
2022-12-19 03:28:35 +00:00
if ( ! addr )
return 0 ;
2021-01-04 00:34:58 +00:00
// Read and enable/disable.
u8 val = i2c_recv_byte ( I2C_5 , addr , reg_addr ) ;
val & = ~ enable_mask ;
2018-05-01 06:15:48 +01:00
if ( enable )
2021-01-04 00:34:58 +00:00
val | = ( enable_val < < enable_shift ) ;
// Set enable.
_max7762x_set_reg ( addr , reg_addr , val ) ;
// Wait for enable/disable ramp delay.
2018-07-04 16:39:26 +01:00
usleep ( 1000 ) ;
2018-05-01 06:15:48 +01:00
return 1 ;
}
2021-01-04 00:34:58 +00:00
void max77620_config_gpio ( u32 gpio_id , bool enable )
2019-02-15 23:23:14 +00:00
{
2021-01-04 00:34:58 +00:00
if ( gpio_id > 7 )
return ;
// Configure as standard GPIO.
u8 val = i2c_recv_byte ( I2C_5 , MAX77620_I2C_ADDR , MAX77620_REG_AME_GPIO ) ;
i2c_send_byte ( I2C_5 , MAX77620_I2C_ADDR , MAX77620_REG_AME_GPIO , val & ~ BIT ( gpio_id ) ) ;
2019-02-15 23:23:14 +00:00
2021-01-04 00:34:58 +00:00
// Set GPIO configuration.
if ( enable )
val = MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DIR_OUTPUT | MAX77620_CNFG_GPIO_DRV_PUSHPULL ;
else
val = MAX77620_CNFG_GPIO_DIR_INPUT | MAX77620_CNFG_GPIO_DRV_OPENDRAIN ;
i2c_send_byte ( I2C_5 , MAX77620_I2C_ADDR , MAX77620_REG_GPIO0 + gpio_id , val ) ;
}
void max77621_config_default ( u32 id , bool por )
{
2019-02-15 23:23:14 +00:00
const max77620_regulator_t * reg = & _pmic_regulators [ id ] ;
2021-01-04 00:34:58 +00:00
if ( reg - > type ! = REGULATOR_BC0 )
return ;
2019-02-15 23:23:14 +00:00
2021-01-04 00:34:58 +00:00
u8 addr = _max7762x_get_i2c_address ( id ) ;
2022-12-19 03:28:35 +00:00
if ( ! addr )
return ;
2019-02-15 23:23:14 +00:00
2021-01-04 00:34:58 +00:00
if ( por )
{
// Set voltage and disable power before changing the inductor.
max7762x_regulator_set_voltage ( id , 1000000 ) ;
max7762x_regulator_enable ( id , false ) ;
// Configure to default.
2022-10-11 01:53:17 +01:00
i2c_send_byte ( I2C_5 , addr , MAX77621_REG_CONTROL1 , reg - > ctrl . ctrl1_por ) ;
i2c_send_byte ( I2C_5 , addr , MAX77621_REG_CONTROL2 , reg - > ctrl . ctrl2_por ) ;
2021-01-04 00:34:58 +00:00
}
else
{
2022-10-11 01:53:17 +01:00
i2c_send_byte ( I2C_5 , addr , MAX77621_REG_CONTROL1 , reg - > ctrl . ctrl1_hos ) ;
i2c_send_byte ( I2C_5 , addr , MAX77621_REG_CONTROL2 , reg - > ctrl . ctrl2_hos ) ;
2021-01-04 00:34:58 +00:00
}
2019-02-15 23:23:14 +00:00
}
2018-05-01 06:15:48 +01:00
void max77620_config_default ( )
{
2021-01-04 00:34:58 +00:00
// Check if Erista OTP.
if ( i2c_recv_byte ( I2C_5 , MAX77620_I2C_ADDR , MAX77620_REG_CID4 ) ! = 0x35 )
return ;
// Set default voltages and enable regulators.
for ( u32 i = 1 ; i < = REGULATOR_LDO8 ; i + + )
2018-05-01 06:15:48 +01:00
{
max77620_regulator_config_fps ( i ) ;
2021-01-04 00:34:58 +00:00
max7762x_regulator_set_voltage ( i , _pmic_regulators [ i ] . uv_default ) ;
if ( _pmic_regulators [ i ] . fps . fps_src ! = MAX77620_FPS_SRC_NONE )
max7762x_regulator_enable ( i , true ) ;
2018-05-01 06:15:48 +01:00
}
2021-01-04 00:34:58 +00:00
// Enable SD0 output voltage sense and disable for SD1. Additionally disable the reserved bit.
_max7762x_set_reg ( MAX77620_I2C_ADDR , MAX77620_REG_SD_CFG2 , MAX77620_SD_CNF2_ROVS_EN_SD0 ) ;
2018-05-01 06:15:48 +01:00
}
2018-07-01 15:01:10 +01:00
2021-04-11 08:20:54 +01:00
// Stock HOS: disabled.
2020-04-06 03:54:45 +01:00
void max77620_low_battery_monitor_config ( bool enable )
2018-07-01 15:01:10 +01:00
{
2021-01-04 00:34:58 +00:00
_max7762x_set_reg ( MAX77620_I2C_ADDR , MAX77620_REG_CNFGGLBL1 ,
MAX77620_CNFGGLBL1_LBDAC_EN |
( enable ? MAX77620_CNFGGLBL1_MPPLD : 0 ) |
MAX77620_CNFGGLBL1_LBHYST_200 |
MAX77620_CNFGGLBL1_LBDAC_2800 ) ;
2018-07-01 15:01:10 +01:00
}