From 94a7fc2cbdd8b32f6a385e4110b4e1476f684ae4 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Mon, 25 Dec 2017 14:53:06 +0800 Subject: [PATCH] mfd: rk808: power off system in syscore shutdown For PMIC that power off supplies by write register via i2c bus, it's better to do power off at syscore shutdown. Because when run to kernel's "pm_power_off" call, i2c may has been stopped or PMIC may not be able to get i2c transfer while there are too many devices are competiting. This patch effects on PMIC: RK808/RK818/RK816, not including RK805 which power off system by pull up pmic sleep pin in ATF. Change-Id: I116f79dc91f6f10c6d8070a9168eea44954bf01f Signed-off-by: Joseph Chen --- drivers/mfd/rk808.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 72dea67722d4..1030066b8200 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -16,6 +16,7 @@ * more details. */ +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include struct rk808_reg_data { int addr; @@ -658,7 +660,7 @@ static void rk808_device_shutdown_prepare(void) } } -static void rk808_device_shutdown(void) +static void rk808_syscore_shutdown(void) { int ret; struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); @@ -676,13 +678,35 @@ static void rk808_device_shutdown(void) regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG, (0x3 << 2), (0x0 << 2)); - if (pm_shutdown) { - ret = pm_shutdown(rk808->regmap); - if (ret) - dev_err(&rk808_i2c_client->dev, "power off error!\n"); + /* + * For PMIC that power off supplies by write register via i2c bus, + * it's better to do power off at syscore shutdown here. + * + * Because when run to kernel's "pm_power_off" call, i2c may has + * 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) { + /* power off supplies ! */ + if (pm_shutdown) { + dev_info(&rk808_i2c_client->dev, "System power off\n"); + ret = pm_shutdown(rk808->regmap); + if (ret) + dev_err(&rk808_i2c_client->dev, + "System power off error!\n"); + mdelay(10); + dev_info(&rk808_i2c_client->dev, + "Cpu should never reach here, stop!\n"); + while (1) + ; + } } } +static struct syscore_ops rk808_syscore_ops = { + .shutdown = rk808_syscore_shutdown, +}; + static ssize_t rk8xx_dbg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -926,7 +950,7 @@ static int rk808_probe(struct i2c_client *client, } if (pm_shutdown_fn) { pm_shutdown = pm_shutdown_fn; - pm_power_off = rk808_device_shutdown; + register_syscore_ops(&rk808_syscore_ops); } } @@ -992,10 +1016,11 @@ static int rk808_remove(struct i2c_client *client) regmap_del_irq_chip(client->irq, rk808->irq_data); mfd_remove_devices(&client->dev); - if (pm_power_off == rk808_device_shutdown) - pm_power_off = NULL; + if (pm_power_off_prepare == rk808_device_shutdown_prepare) pm_power_off_prepare = NULL; + if (pm_shutdown) + unregister_syscore_ops(&rk808_syscore_ops); return 0; }