From c45169cd0880e075f46e187feaad50be441f3c16 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Tue, 5 Nov 2019 20:42:53 +0800 Subject: [PATCH] mfd: rk808: power off system in syscore shutdown The i2c maybe stopped before pm_power_off() is called, which results in the PMIC power off failure issue. Moving PMIC power off operation to syscore shutdown is better. Change-Id: Ib43827ebd49059719b8899f90a696b6c32a6ddd1 Signed-off-by: Joseph Chen --- drivers/mfd/rk808.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 2807f554eda6..943475636f88 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -840,6 +840,9 @@ static void rk818_device_shutdown(void) dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n"); } +/* Called in syscore shutdown */ +static void (*pm_shutdown)(void); + static void rk8xx_syscore_shutdown(void) { int ret; @@ -866,15 +869,26 @@ static void rk8xx_syscore_shutdown(void) * been stopped or PMIC may not be able to get i2c transfer while * there are too many devices are competiting. */ - if (system_state == SYSTEM_POWER_OFF && - (rk808->variant == RK809_ID || rk808->variant == RK817_ID)) { - ret = regmap_update_bits(rk808->regmap, - RK817_SYS_CFG(3), - RK817_SLPPIN_FUNC_MSK, - SLPPIN_DN_FUN); - if (ret) { - dev_warn(&rk808_i2c_client->dev, - "Cannot switch to power down function\n"); + if (system_state == SYSTEM_POWER_OFF) { + if (rk808->variant == RK809_ID || rk808->variant == RK817_ID) { + ret = regmap_update_bits(rk808->regmap, + RK817_SYS_CFG(3), + RK817_SLPPIN_FUNC_MSK, + SLPPIN_DN_FUN); + if (ret) { + dev_warn(&rk808_i2c_client->dev, + "Cannot switch to power down function\n"); + } + } + + if (pm_shutdown) { + dev_info(&rk808_i2c_client->dev, "System power off\n"); + pm_shutdown(); + mdelay(10); + dev_info(&rk808_i2c_client->dev, + "Power off failed !\n"); + while (1) + ; } } } @@ -1254,7 +1268,6 @@ static int rk808_probe(struct i2c_client *client, nr_cells = ARRAY_SIZE(rk817s); on_source = RK817_ON_SOURCE_REG; off_source = RK817_OFF_SOURCE_REG; - register_syscore_ops(&rk808_syscore_ops); suspend_reg = rk817_suspend_reg; suspend_reg_num = ARRAY_SIZE(rk817_suspend_reg); resume_reg = rk817_resume_reg; @@ -1357,8 +1370,12 @@ static int rk808_probe(struct i2c_client *client, if (pm_off) { if (!pm_power_off_prepare) pm_power_off_prepare = rk808->pm_pwroff_prep_fn; - if (!pm_power_off_prepare) - pm_power_off = rk808->pm_pwroff_fn; + + if (rk808->pm_pwroff_fn) { + register_syscore_ops(&rk808_syscore_ops); + /* power off system in the syscore shutdown ! */ + pm_shutdown = rk808->pm_pwroff_fn; + } } rk8xx_kobj = kobject_create_and_add("rk8xx", NULL); @@ -1401,6 +1418,9 @@ static int rk808_remove(struct i2c_client *client) pm_power_off_prepare == rk808->pm_pwroff_prep_fn) pm_power_off_prepare = NULL; + if (pm_shutdown) + unregister_syscore_ops(&rk808_syscore_ops); + return 0; }