From b711dfd7efe97b0c9e6461573dc6e6bf5640f964 Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Tue, 12 Nov 2024 16:43:49 +0800 Subject: [PATCH] mfd: rk806: Support power-supply grouping to enter sleep mode In order to support the suspend/resume power supply sequence, the power supplies are grouped and controlled in stages to enter sleep mode. Change-Id: I16cb53b01b86a8b221de91a62c5ffddfa34e0f33 Signed-off-by: Shengfei Xu --- drivers/mfd/rk806-core.c | 18 ++++++++++++++- drivers/regulator/rk806-regulator.c | 36 ++++++++++++++++++++++++++--- include/linux/mfd/rk806.h | 2 ++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/rk806-core.c b/drivers/mfd/rk806-core.c index 7da7185763f4..eed82776374b 100644 --- a/drivers/mfd/rk806-core.c +++ b/drivers/mfd/rk806-core.c @@ -214,7 +214,7 @@ static const struct reg_field rk806_reg_fields[] = { [NLDO3_VSEL_CTR_SEL] = REG_FIELD(0x6a, 0, 1), /* SLEEP_VSEL_CTR_SEL4 */ [PLDO4_VSEL_CTR_SEL] = REG_FIELD(0x6d, 4, 5), - [PLDO3_VSEL_CTR_SEL] = REG_FIELD(0x6d, 0, 0), + [PLDO3_VSEL_CTR_SEL] = REG_FIELD(0x6d, 0, 1), [PLDO2_VSEL_CTR_SEL] = REG_FIELD(0x6c, 4, 5), [PLDO1_VSEL_CTR_SEL] = REG_FIELD(0x6c, 0, 1), /* SLEEP_VSEL_CTR_SEL5 */ @@ -820,6 +820,22 @@ static int rk806_parse_dt(struct rk806 *rk806) dev_info(dev, "vb-shutdown-sequence missing!\n"); } + pdata->dvs_control_suspend = devm_kzalloc(dev, + RK806_ID_END * sizeof(int), + GFP_KERNEL); + if (!pdata->dvs_control_suspend) + return -EINVAL; + + pdata->support_dvs_control_suspend = 1; + ret = device_property_read_u32_array(dev, + "dvs-suspend-control-by", + pdata->dvs_control_suspend, + RK806_ID_END); + if (ret) { + pdata->support_dvs_control_suspend = 0; + dev_info(dev, "dvs-suspend-control-by missing!\n"); + } + return 0; } diff --git a/drivers/regulator/rk806-regulator.c b/drivers/regulator/rk806-regulator.c index bbef6dee2d62..b8b18fd63e51 100644 --- a/drivers/regulator/rk806-regulator.c +++ b/drivers/regulator/rk806-regulator.c @@ -1178,6 +1178,8 @@ static int rk806_regulator_probe(struct platform_device *pdev) static int __maybe_unused rk806_suspend(struct device *dev) { struct rk806 *rk806 = dev_get_drvdata(dev->parent); + struct rk806_platform_data *pdata = rk806->pdata; + int value; int i; rk806_field_write(rk806, RST_FUN, 0x00); @@ -1186,10 +1188,35 @@ static int __maybe_unused rk806_suspend(struct device *dev) for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_NO_EFFECT); - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN); + if (!pdata->dvs_control_suspend || !pdata->support_dvs_control_suspend) { + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN); - for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) - rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_PWRCTRL1); + for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) + rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_PWRCTRL1); + } else { + for (i = 0; i <= RK806_ID_PLDO6 - RK806_ID_PLDO1; i++) { + value = rk806_field_read(rk806, PLDO1_ON_VSEL + i); + rk806_field_write(rk806, PLDO1_SLP_VSEL + i, value); + } + + for (i = RK806_ID_DCDC1; i <= RK806_ID_NLDO5; i++) + rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, + pdata->dvs_control_suspend[i]); + rk806_field_write(rk806, PLDO1_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO6]); + rk806_field_write(rk806, PLDO2_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO1]); + rk806_field_write(rk806, PLDO3_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO2]); + rk806_field_write(rk806, PLDO4_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO3]); + rk806_field_write(rk806, PLDO5_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO4]); + rk806_field_write(rk806, PLDO6_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO5]); + + for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) { + if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL2) + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_DVS_FUN); + if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL3) + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_DVS_FUN); + } + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_SLP_FUN); + } return 0; } @@ -1203,6 +1230,9 @@ 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, PWRCTRL2_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, RST_FUN, 0x01); return 0; diff --git a/include/linux/mfd/rk806.h b/include/linux/mfd/rk806.h index f97602d73e39..e0d608480ce5 100644 --- a/include/linux/mfd/rk806.h +++ b/include/linux/mfd/rk806.h @@ -505,9 +505,11 @@ struct rk806_platform_data { int *shutdown_sequence; int *vb_shutdown_sequence; + int *dvs_control_suspend; int support_shutdown_sequence; int support_vb_sequence; + int support_dvs_control_suspend; }; struct rk806_pin_info {