rv1126 rv1109系统关机功能的分析与实现
关机代码分析
代码在./kernel/reboot.c 中
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
if (pm_power_off_prepare)
pm_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown();
pr_emerg("Power down\n");
kmsg_dump(KMSG_DUMP_POWEROFF);
machine_power_off();
}
kernel_power_off 的调用关系图如下
调用kernel_power_off 的有几个地方,一是do_poweroff Sys-Rq 用,一个是温度过高时关机,另一个是reboot.c中处理poweroff 命令行的系统调用。
//SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
// void __user *, arg)
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
跟踪kernel_power_off -> syscore_shutdown
void syscore_shutdown(void)
{
struct syscore_ops *ops;
mutex_lock(&syscore_ops_lock);
list_for_each_entry_reverse(ops, &syscore_ops_list, node)
if (ops->shutdown) {
if (initcall_debug)
pr_info("PM: Calling %pF\n", ops->shutdown);
ops->shutdown();
}
mutex_unlock(&syscore_ops_lock);
}
查看syscore_ops_list 到底有哪些,
其它地方的不影响关机断电,主要是挂起等相关的一些操作。
rk808.c中
static struct syscore_ops rk808_syscore_ops = {
.shutdown = rk8xx_syscore_shutdown,
};
static void rk8xx_syscore_shutdown(void)
{
int ret;
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
if (!rk808) {
dev_warn(&rk808_i2c_client->dev,
"have no rk808, so do nothing here\n");
return;
}
/* close rtc int when power off */
regmap_update_bits(rk808->regmap,
RK808_INT_STS_MSK_REG1,
(0x3 << 5), (0x3 << 5));
regmap_update_bits(rk808->regmap,
RK808_RTC_INT_REG,
(0x3 << 2), (0x0 << 2));
/*
* 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) {
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)
;
}
}
}
rv1109 使用的是rk809的PMIC,驱动与rk808共用。给PMIC 通过IIC发送关机指令。
machine_power_off 在这里其实没起作用,代码分析如下:
void machine_power_off(void)
{
local_irq_disable();
smp_send_stop();
if (pm_power_off)
pm_power_off();
}
static int rk808_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
............
if (!pm_power_off)
pm_power_off = rk808_pm_power_off_dummy;
............
}
static void rk808_pm_power_off_dummy(void)
{
pr_info("Dummy power off for RK8xx PMICs, should never reach here!\n");
while (1)
;
}
硬件关联
关机实现
驱动实现
直接调用kernel_power_off 函数
应用程序实现
直接运行命令poweroff