mfd: rk806: config the power off sequence

Configure the power-off timing of each power supply of the PMIC
during normal shutdown through the "shutdown-sequence".
Configure the power-off timing of each power supply of PMIC
during low power forced shutdown through "vb-shutdown-sequence".
Press the RESET button in sleep mode, and the PMIC will power down
and then power on. The PMIC's power on sequence follows
the power on sequence.

Change-Id: Iebd0ea604fe5419dcead8fa75ade1402cabf7461
Signed-off-by: Shengfei Xu <xsf@rock-chips.com>
This commit is contained in:
Shengfei Xu
2024-09-28 10:39:43 +08:00
committed by Tao Huang
parent a3f03c79ff
commit b2dcf7ae10
3 changed files with 141 additions and 4 deletions

View File

@@ -280,6 +280,43 @@ static const struct reg_field rk806_reg_fields[] = {
[INT_FUNCTION] = REG_FIELD(0x7b, 2, 2),
[INT_POL] = REG_FIELD(0x7b, 1, 1),
[INT_FC_EN] = REG_FIELD(0x7b, 0, 0),
[BUCK1_SEQ] = REG_FIELD(0xB2, 0, 5),
[BUCK2_SEQ] = REG_FIELD(0xB3, 0, 5),
[BUCK3_SEQ] = REG_FIELD(0xB4, 0, 5),
[BUCK4_SEQ] = REG_FIELD(0xB5, 0, 5),
[BUCK5_SEQ] = REG_FIELD(0xB6, 0, 5),
[BUCK6_SEQ] = REG_FIELD(0xB7, 0, 5),
[BUCK7_SEQ] = REG_FIELD(0xB8, 0, 5),
[BUCK8_SEQ] = REG_FIELD(0xB9, 0, 5),
[BUCK9_SEQ] = REG_FIELD(0xBA, 0, 5),
[BUCK10_SEQ] = REG_FIELD(0xBB, 0, 5),
[NLDO1_SEQ] = REG_FIELD(0xBC, 0, 5),
[NLDO2_SEQ] = REG_FIELD(0xBD, 0, 5),
[NLDO3_SEQ] = REG_FIELD(0xBE, 0, 5),
[NLDO4_SEQ] = REG_FIELD(0xBF, 0, 5),
[NLDO5_SEQ] = REG_FIELD(0xC0, 0, 5),
[PLDO6_45_SEQ] = REG_FIELD(0xB5, 6, 7),
[PLDO6_23_SEQ] = REG_FIELD(0xB6, 6, 7),
[PLDO6_01_SEQ] = REG_FIELD(0xB7, 6, 7),
[PLDO1_45_SEQ] = REG_FIELD(0xB8, 6, 7),
[PLDO1_23_SEQ] = REG_FIELD(0xB9, 6, 7),
[PLDO1_01_SEQ] = REG_FIELD(0xBA, 6, 7),
[PLDO2_45_SEQ] = REG_FIELD(0xBB, 6, 7),
[PLDO2_23_SEQ] = REG_FIELD(0xBC, 6, 7),
[PLDO2_01_SEQ] = REG_FIELD(0xBD, 6, 7),
[PLDO3_45_SEQ] = REG_FIELD(0xBE, 6, 7),
[PLDO3_23_SEQ] = REG_FIELD(0xBF, 6, 7),
[PLDO3_01_SEQ] = REG_FIELD(0xC0, 6, 7),
[PLDO4_SEQ] = REG_FIELD(0xC1, 0, 5),
[PLDO5_SEQ] = REG_FIELD(0xC2, 0, 5),
[BUCK9_RATE2] = REG_FIELD(0xEA, 0, 0),
[BUCK10_RATE2] = REG_FIELD(0xEA, 1, 1),
[LDO_RATE] = REG_FIELD(0xEA, 3, 5),
@@ -512,6 +549,55 @@ int rk806_field_write(struct rk806 *rk806,
}
EXPORT_SYMBOL_GPL(rk806_field_write);
static void rk806_vb_requence_config(struct rk806 *rk806)
{
struct rk806_platform_data *pdata = rk806->pdata;
int i;
if (!pdata->support_vb_sequence || !pdata->vb_shutdown_sequence)
return;
for (i = RK806_ID_DCDC1; i <= RK806_ID_DCDC10; i++)
rk806_field_write(rk806, BUCK1_SEQ + i, pdata->vb_shutdown_sequence[i]);
for (i = RK806_ID_NLDO1; i <= RK806_ID_NLDO5; i++)
rk806_field_write(rk806,
NLDO1_SEQ + (i - RK806_ID_NLDO1),
pdata->vb_shutdown_sequence[i]);
rk806_field_write(rk806, PLDO1_01_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO1]);
rk806_field_write(rk806, PLDO2_01_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO2]);
rk806_field_write(rk806, PLDO3_01_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO3]);
rk806_field_write(rk806, PLDO4_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO4]);
rk806_field_write(rk806, PLDO5_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO5]);
rk806_field_write(rk806, PLDO6_01_SEQ, pdata->vb_shutdown_sequence[RK806_ID_PLDO6]);
}
void rk806_shutdown_requence_config(struct rk806 *rk806)
{
struct rk806_platform_data *pdata = rk806->pdata;
int i;
if (!pdata->support_shutdown_sequence || !pdata->shutdown_sequence)
return;
for (i = RK806_ID_DCDC1; i <= RK806_ID_DCDC10; i++)
rk806_field_write(rk806, BUCK1_SEQ + i, pdata->shutdown_sequence[i]);
for (i = RK806_ID_NLDO1; i <= RK806_ID_NLDO5; i++)
rk806_field_write(rk806,
NLDO1_SEQ + (i - RK806_ID_NLDO1),
pdata->shutdown_sequence[i]);
rk806_field_write(rk806, PLDO1_01_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO1]);
rk806_field_write(rk806, PLDO2_01_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO2]);
rk806_field_write(rk806, PLDO3_01_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO3]);
rk806_field_write(rk806, PLDO4_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO4]);
rk806_field_write(rk806, PLDO5_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO5]);
rk806_field_write(rk806, PLDO6_01_SEQ, pdata->shutdown_sequence[RK806_ID_PLDO6]);
}
EXPORT_SYMBOL_GPL(rk806_shutdown_requence_config);
static void rk806_irq_init(struct rk806 *rk806)
{
/* INT pin polarity active low */
@@ -576,6 +662,7 @@ static void rk806_vb_force_shutdown_init(struct rk806 *rk806)
{
struct rk806_platform_data *pdata = rk806->pdata;
rk806_vb_requence_config(rk806);
rk806_field_write(rk806, VB_LO_ACT, VB_LO_ACT_SD);
rk806_field_write(rk806, VB_LO_SEL,
(pdata->low_voltage_threshold - 2800) / 100);
@@ -701,6 +788,38 @@ static int rk806_parse_dt(struct rk806 *rk806)
if (device_property_read_bool(dev, "vdc-wakeup-enable"))
pdata->vdc_wakeup_enable = 1;
pdata->shutdown_sequence = devm_kzalloc(dev,
RK806_ID_END * sizeof(int),
GFP_KERNEL);
if (!pdata->shutdown_sequence)
return -EINVAL;
pdata->support_shutdown_sequence = 1;
ret = device_property_read_u32_array(dev,
"shutdown-sequence",
pdata->shutdown_sequence,
RK806_ID_END);
if (ret) {
dev_info(dev, "shutdown-sequence missing!\n");
pdata->support_shutdown_sequence = 0;
}
pdata->vb_shutdown_sequence = devm_kzalloc(dev,
RK806_ID_END * sizeof(int),
GFP_KERNEL);
if (!pdata->vb_shutdown_sequence)
return -EINVAL;
pdata->support_vb_sequence = 1;
ret = device_property_read_u32_array(dev,
"vb-shutdown-sequence",
pdata->vb_shutdown_sequence,
RK806_ID_END);
if (ret) {
pdata->support_vb_sequence = 0;
dev_info(dev, "vb-shutdown-sequence missing!\n");
}
return 0;
}

View File

@@ -1180,6 +1180,7 @@ static int __maybe_unused rk806_suspend(struct device *dev)
struct rk806 *rk806 = dev_get_drvdata(dev->parent);
int i;
rk806_field_write(rk806, RST_FUN, 0x00);
rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN);
for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++)
@@ -1202,6 +1203,7 @@ static int __maybe_unused rk806_resume(struct device *dev)
rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_NO_EFFECT);
rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN);
rk806_field_write(rk806, RST_FUN, 0x01);
return 0;
}
@@ -1211,14 +1213,14 @@ static void rk806_regulator_shutdown(struct platform_device *pdev)
{
struct rk806 *rk806 = dev_get_drvdata(pdev->dev.parent);
if (system_state == SYSTEM_POWER_OFF)
if (system_state == SYSTEM_POWER_OFF) {
rk806_shutdown_requence_config(rk806);
if ((rk806->pins->p) && (rk806->pins->power_off))
pinctrl_select_state(rk806->pins->p, rk806->pins->power_off);
}
if (system_state == SYSTEM_RESTART)
if ((rk806->pins->p) && (rk806->pins->reset))
pinctrl_select_state(rk806->pins->p, rk806->pins->reset);
}
static const struct platform_device_id rk806_regulator_id_table[] = {

View File

@@ -482,6 +482,16 @@ enum rk806_fields {
LDO_RATE, BUCK1_RATE2, BUCK2_RATE2, BUCK3_RATE2, BUCK4_RATE2,
BUCK5_RATE2, BUCK6_RATE2, BUCK7_RATE2, BUCK8_RATE2, BUCK9_RATE2,
BUCK10_RATE2,
BUCK1_SEQ, BUCK2_SEQ, BUCK3_SEQ, BUCK4_SEQ, BUCK5_SEQ,
BUCK6_SEQ, BUCK7_SEQ, BUCK8_SEQ, BUCK9_SEQ, BUCK10_SEQ,
PLDO1_01_SEQ, PLDO1_23_SEQ, PLDO1_45_SEQ,
PLDO2_01_SEQ, PLDO2_23_SEQ, PLDO2_45_SEQ,
PLDO3_01_SEQ, PLDO3_23_SEQ, PLDO3_45_SEQ,
PLDO4_SEQ, PLDO5_SEQ,
PLDO6_01_SEQ, PLDO6_23_SEQ, PLDO6_45_SEQ,
NLDO1_SEQ, NLDO2_SEQ, NLDO3_SEQ, NLDO4_SEQ, NLDO5_SEQ,
F_MAX_FIELDS
};
@@ -492,6 +502,12 @@ struct rk806_platform_data {
int shutdown_temperture_threshold;
int hotdie_temperture_threshold;
int vdc_wakeup_enable;
int *shutdown_sequence;
int *vb_shutdown_sequence;
int support_shutdown_sequence;
int support_vb_sequence;
};
struct rk806_pin_info {
@@ -517,7 +533,6 @@ struct rk806 {
struct regmap_irq_chip_data *irq_data;
struct rk806_platform_data *pdata;
struct rk806_pin_info *pins;
int vb_lo_irq;
};
extern const struct regmap_config rk806_regmap_config;
@@ -529,4 +544,5 @@ int rk806_field_write(struct rk806 *rk806,
unsigned int val);
int rk806_field_read(struct rk806 *rk806,
enum rk806_fields field_id);
void rk806_shutdown_requence_config(struct rk806 *rk806);
#endif /* __LINUX_REGULATOR_RK806_H */