From b2dcf7ae10c6d27a98fa15c9e3ff01b5ddba41bc Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Sat, 28 Sep 2024 10:39:43 +0800 Subject: [PATCH] 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 --- drivers/mfd/rk806-core.c | 119 ++++++++++++++++++++++++++++ drivers/regulator/rk806-regulator.c | 8 +- include/linux/mfd/rk806.h | 18 ++++- 3 files changed, 141 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/rk806-core.c b/drivers/mfd/rk806-core.c index 2de93a08e4df..7da7185763f4 100644 --- a/drivers/mfd/rk806-core.c +++ b/drivers/mfd/rk806-core.c @@ -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; } diff --git a/drivers/regulator/rk806-regulator.c b/drivers/regulator/rk806-regulator.c index 706fb0b6d52b..bbef6dee2d62 100644 --- a/drivers/regulator/rk806-regulator.c +++ b/drivers/regulator/rk806-regulator.c @@ -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[] = { diff --git a/include/linux/mfd/rk806.h b/include/linux/mfd/rk806.h index e6181bb24257..f97602d73e39 100644 --- a/include/linux/mfd/rk806.h +++ b/include/linux/mfd/rk806.h @@ -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 */