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 <chenjh@rock-chips.com>
This commit is contained in:
Joseph Chen 2017-12-25 14:53:06 +08:00 committed by Tao Huang
commit 94a7fc2cbd

View file

@ -16,6 +16,7 @@
* more details.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@ -24,6 +25,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/syscore_ops.h>
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;
}