mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-25 14:25:44 +00:00
feat(stpmic1): add new services
Add support for ICC, sink mode, bypass mode, active discharge and list voltages. Handle LDO3 sink source mode in a different way to avoid setting voltage while in sink source mode. Change-Id: Ib1b909fd8a153f542917f650e43e24317a570534 Signed-off-by: Pascal Paillet <p.paillet@st.com>
This commit is contained in:
parent
13fbfe046e
commit
ea552bf5a5
2 changed files with 160 additions and 4 deletions
|
@ -23,10 +23,17 @@ struct regul_struct {
|
|||
uint8_t pull_down;
|
||||
uint8_t mask_reset_reg;
|
||||
uint8_t mask_reset;
|
||||
uint8_t icc_reg;
|
||||
uint8_t icc_mask;
|
||||
};
|
||||
|
||||
static struct i2c_handle_s *pmic_i2c_handle;
|
||||
static uint16_t pmic_i2c_addr;
|
||||
/*
|
||||
* Special mode corresponds to LDO3 in sink source mode or in bypass mode.
|
||||
* LDO3 doesn't switch back from special to normal mode.
|
||||
*/
|
||||
static bool ldo3_special_mode;
|
||||
|
||||
/* Voltage tables in mV */
|
||||
static const uint16_t buck1_voltage_table[] = {
|
||||
|
@ -347,8 +354,11 @@ static const uint16_t ldo3_voltage_table[] = {
|
|||
3300,
|
||||
3300,
|
||||
3300,
|
||||
500,
|
||||
0xFFFF, /* VREFDDR */
|
||||
};
|
||||
|
||||
/* Special mode table is used for sink source OR bypass mode */
|
||||
static const uint16_t ldo3_special_mode_table[] = {
|
||||
0,
|
||||
};
|
||||
|
||||
static const uint16_t ldo5_voltage_table[] = {
|
||||
|
@ -438,6 +448,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK1_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK1_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck2",
|
||||
|
@ -450,6 +462,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK2_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK2_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK2_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck3",
|
||||
|
@ -462,6 +476,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK3_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK3_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK3_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck4",
|
||||
|
@ -474,6 +490,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK4_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK4_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK4_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo1",
|
||||
|
@ -484,6 +502,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO1_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO1_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo2",
|
||||
|
@ -494,6 +514,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO2_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO2_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO2_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo3",
|
||||
|
@ -504,6 +526,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO3_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO3_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO3_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo4",
|
||||
|
@ -514,6 +538,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO4_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO4_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO4_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo5",
|
||||
|
@ -524,6 +550,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO5_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO5_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO5_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo6",
|
||||
|
@ -534,6 +562,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO6_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO6_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO6_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "vref_ddr",
|
||||
|
@ -551,6 +581,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = BOOST_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BOOST_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "pwr_sw1",
|
||||
|
@ -558,6 +590,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = USBSW_OTG_SWITCH_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = PWR_SW1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "pwr_sw2",
|
||||
|
@ -565,6 +599,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = SWIN_SWOUT_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = PWR_SW2_ICC_SHIFT,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -649,11 +685,21 @@ int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
|
|||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
uint8_t mask;
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
/*
|
||||
* when the LDO3 is in special mode, we do not change voltage,
|
||||
* because by setting voltage, the LDO would leaves sink-source
|
||||
* mode. There is obviously no reason to leave sink-source mode
|
||||
* at runtime.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
|
||||
if (strncmp(name, "buck", 4) == 0) {
|
||||
mask = BUCK_VOLTAGE_MASK;
|
||||
} else if ((strncmp(name, "ldo", 3) == 0) &&
|
||||
(strncmp(name, "ldo4", 4) != 0)) {
|
||||
(strncmp(name, "ldo4", 5) != 0)) {
|
||||
mask = LDO_VOLTAGE_MASK;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -682,12 +728,90 @@ int stpmic1_regulator_mask_reset_set(const char *name)
|
|||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if (regul->mask_reset_reg == 0U) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return stpmic1_register_update(regul->mask_reset_reg,
|
||||
BIT(regul->mask_reset),
|
||||
LDO_BUCK_RESET_MASK <<
|
||||
regul->mask_reset);
|
||||
}
|
||||
|
||||
int stpmic1_regulator_icc_set(const char *name)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if (regul->mask_reset_reg == 0U) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return stpmic1_register_update(regul->icc_reg,
|
||||
BIT(regul->icc_mask),
|
||||
BIT(regul->icc_mask));
|
||||
}
|
||||
|
||||
int stpmic1_regulator_sink_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "ldo3", 5) != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ldo3_special_mode = true;
|
||||
|
||||
/* disable bypass mode, enable sink mode */
|
||||
return stpmic1_register_update(LDO3_CONTROL_REG,
|
||||
LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT,
|
||||
LDO3_BYPASS | LDO_VOLTAGE_MASK);
|
||||
}
|
||||
|
||||
int stpmic1_regulator_bypass_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "ldo3", 5) != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ldo3_special_mode = true;
|
||||
|
||||
/* enable bypass mode, disable sink mode */
|
||||
return stpmic1_register_update(LDO3_CONTROL_REG,
|
||||
LDO3_BYPASS,
|
||||
LDO3_BYPASS | LDO_VOLTAGE_MASK);
|
||||
}
|
||||
|
||||
int stpmic1_active_discharge_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "pwr_sw1", 8) == 0) {
|
||||
return stpmic1_register_update(USB_CONTROL_REG,
|
||||
VBUS_OTG_DISCHARGE,
|
||||
VBUS_OTG_DISCHARGE);
|
||||
}
|
||||
|
||||
if (strncmp(name, "pwr_sw2", 8) == 0) {
|
||||
return stpmic1_register_update(USB_CONTROL_REG,
|
||||
SW_OUT_DISCHARGE,
|
||||
SW_OUT_DISCHARGE);
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
|
||||
size_t *levels_count)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
*levels_count = ARRAY_SIZE(ldo3_special_mode_table);
|
||||
*levels = ldo3_special_mode_table;
|
||||
} else {
|
||||
*levels_count = regul->voltage_table_size;
|
||||
*levels = regul->voltage_table;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stpmic1_regulator_voltage_get(const char *name)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
@ -695,11 +819,15 @@ int stpmic1_regulator_voltage_get(const char *name)
|
|||
uint8_t mask;
|
||||
int status;
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
|
||||
if (strncmp(name, "buck", 4) == 0) {
|
||||
mask = BUCK_VOLTAGE_MASK;
|
||||
} else if ((strncmp(name, "ldo", 3) == 0) &&
|
||||
(strncmp(name, "ldo4", 4) != 0)) {
|
||||
(strncmp(name, "ldo4", 5) != 0)) {
|
||||
mask = LDO_VOLTAGE_MASK;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
@ -103,6 +103,22 @@
|
|||
#define BUCK4_PULL_DOWN_SHIFT 6
|
||||
#define VREF_DDR_PULL_DOWN_SHIFT 4
|
||||
|
||||
/* ICC register */
|
||||
#define BUCK1_ICC_SHIFT 0
|
||||
#define BUCK2_ICC_SHIFT 1
|
||||
#define BUCK3_ICC_SHIFT 2
|
||||
#define BUCK4_ICC_SHIFT 3
|
||||
#define PWR_SW1_ICC_SHIFT 4
|
||||
#define PWR_SW2_ICC_SHIFT 5
|
||||
#define BOOST_ICC_SHIFT 6
|
||||
|
||||
#define LDO1_ICC_SHIFT 0
|
||||
#define LDO2_ICC_SHIFT 1
|
||||
#define LDO3_ICC_SHIFT 2
|
||||
#define LDO4_ICC_SHIFT 3
|
||||
#define LDO5_ICC_SHIFT 4
|
||||
#define LDO6_ICC_SHIFT 5
|
||||
|
||||
/* Buck Mask reset register */
|
||||
#define BUCK1_MASK_RESET 0
|
||||
#define BUCK2_MASK_RESET 1
|
||||
|
@ -118,6 +134,10 @@
|
|||
#define LDO6_MASK_RESET 5
|
||||
#define VREF_DDR_MASK_RESET 6
|
||||
|
||||
/* LDO3 Special modes */
|
||||
#define LDO3_BYPASS BIT(7)
|
||||
#define LDO3_DDR_SEL 31U
|
||||
|
||||
/* Main PMIC Control Register (MAIN_CONTROL_REG) */
|
||||
#define ICC_EVENT_ENABLED BIT(4)
|
||||
#define PWRCTRL_POLARITY_HIGH BIT(3)
|
||||
|
@ -145,6 +165,8 @@
|
|||
/* USB Control Register */
|
||||
#define BOOST_OVP_DISABLED BIT(7)
|
||||
#define VBUS_OTG_DETECTION_DISABLED BIT(6)
|
||||
#define SW_OUT_DISCHARGE BIT(5)
|
||||
#define VBUS_OTG_DISCHARGE BIT(4)
|
||||
#define OCP_LIMIT_HIGH BIT(3)
|
||||
#define SWIN_SWOUT_ENABLED BIT(2)
|
||||
#define USBSW_OTG_SWITCH_ENABLED BIT(1)
|
||||
|
@ -159,9 +181,15 @@ int stpmic1_regulator_enable(const char *name);
|
|||
int stpmic1_regulator_disable(const char *name);
|
||||
bool stpmic1_is_regulator_enabled(const char *name);
|
||||
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
|
||||
int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
|
||||
size_t *levels_count);
|
||||
int stpmic1_regulator_voltage_get(const char *name);
|
||||
int stpmic1_regulator_pull_down_set(const char *name);
|
||||
int stpmic1_regulator_mask_reset_set(const char *name);
|
||||
int stpmic1_regulator_icc_set(const char *name);
|
||||
int stpmic1_regulator_sink_mode_set(const char *name);
|
||||
int stpmic1_regulator_bypass_mode_set(const char *name);
|
||||
int stpmic1_active_discharge_mode_set(const char *name);
|
||||
void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
|
||||
|
||||
int stpmic1_get_version(unsigned long *version);
|
||||
|
|
Loading…
Add table
Reference in a new issue