soc: qcom: Add snapshot of reboot reason driver

This is a snapshot of the reboot reason driver as of msm-5.15
commit <908a517b050d> ("Merge "sched/walt: remove duplicate
definitions of rt_task_arrival_time"").

Change-Id: I7cf898ac8d4232d1e00a58f97091ebc2e52fcb5b
Signed-off-by: Huang Yiwei <quic_hyiwei@quicinc.com>
This commit is contained in:
Huang Yiwei 2022-04-06 21:15:03 +08:00
parent 61003ac51b
commit d2e521397e
3 changed files with 121 additions and 0 deletions

View File

@ -134,6 +134,15 @@ config POWER_RESET_QCOM_PON
power-on and reboot reason, Say Y.
If unsure, Say N.
config POWER_RESET_QCOM_REBOOT_REASON
tristate "MSM reboot mode driver"
depends on ARCH_QCOM
help
Support for setting reboot reason on MSM boards.
This feature supports commands such as "reboot bootloader"
to boot the MSM board to fastboot mode.
If unsure, say Y.
config POWER_RESET_OCELOT_RESET
bool "Microsemi Ocelot reset driver"
depends on MSCC_OCELOT || ARCH_SPARX5 || COMPILE_TEST

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
obj-$(CONFIG_POWER_RESET_QCOM_REBOOT_REASON) += qcom-reboot-reason.o
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o

View File

@ -0,0 +1,111 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/of_address.h>
#include <linux/nvmem-consumer.h>
struct qcom_reboot_reason {
struct device *dev;
struct notifier_block reboot_nb;
struct nvmem_cell *nvmem_cell;
};
struct poweroff_reason {
const char *cmd;
unsigned char pon_reason;
};
static struct poweroff_reason reasons[] = {
{ "recovery", 0x01 },
{ "bootloader", 0x02 },
{ "rtc", 0x03 },
{ "dm-verity device corrupted", 0x04 },
{ "dm-verity enforcing", 0x05 },
{ "keys clear", 0x06 },
{}
};
static int qcom_reboot_reason_reboot(struct notifier_block *this,
unsigned long event, void *ptr)
{
char *cmd = ptr;
struct qcom_reboot_reason *reboot = container_of(this,
struct qcom_reboot_reason, reboot_nb);
struct poweroff_reason *reason;
if (!cmd)
return NOTIFY_OK;
for (reason = reasons; reason->cmd; reason++) {
if (!strcmp(cmd, reason->cmd)) {
nvmem_cell_write(reboot->nvmem_cell,
&reason->pon_reason,
sizeof(reason->pon_reason));
break;
}
}
return NOTIFY_OK;
}
static int qcom_reboot_reason_probe(struct platform_device *pdev)
{
struct qcom_reboot_reason *reboot;
reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
if (!reboot)
return -ENOMEM;
reboot->dev = &pdev->dev;
reboot->nvmem_cell = nvmem_cell_get(reboot->dev, "restart_reason");
if (IS_ERR(reboot->nvmem_cell))
return PTR_ERR(reboot->nvmem_cell);
reboot->reboot_nb.notifier_call = qcom_reboot_reason_reboot;
reboot->reboot_nb.priority = 255;
register_reboot_notifier(&reboot->reboot_nb);
platform_set_drvdata(pdev, reboot);
return 0;
}
static int qcom_reboot_reason_remove(struct platform_device *pdev)
{
struct qcom_reboot_reason *reboot = platform_get_drvdata(pdev);
unregister_reboot_notifier(&reboot->reboot_nb);
return 0;
}
static const struct of_device_id of_qcom_reboot_reason_match[] = {
{ .compatible = "qcom,reboot-reason", },
{},
};
MODULE_DEVICE_TABLE(of, of_qcom_reboot_reason_match);
static struct platform_driver qcom_reboot_reason_driver = {
.probe = qcom_reboot_reason_probe,
.remove = qcom_reboot_reason_remove,
.driver = {
.name = "qcom-reboot-reason",
.of_match_table = of_match_ptr(of_qcom_reboot_reason_match),
},
};
module_platform_driver(qcom_reboot_reason_driver);
MODULE_DESCRIPTION("MSM Reboot Reason Driver");
MODULE_LICENSE("GPL v2");