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:
parent
2741859988
commit
94a7fc2cbd
1 changed files with 33 additions and 8 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue