mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
power: reset: reboot-mode: support parse boot mode
Parse boot mode on system bootup, and export it to userspace by sysfs: sys/kernel/boot_mode Change-Id: I0158fc28f4dae51c798806006e49cead4ce2e923 Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
This commit is contained in:
@@ -10,9 +10,11 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "reboot-mode.h"
|
||||
|
||||
#define PREFIX "mode-"
|
||||
@@ -26,9 +28,21 @@ struct mode_info {
|
||||
struct reboot_mode_driver {
|
||||
struct list_head head;
|
||||
int (*write)(int magic);
|
||||
int (*read)(void);
|
||||
struct notifier_block reboot_notifier;
|
||||
struct notifier_block panic_notifier;
|
||||
};
|
||||
|
||||
static char *boot_mode = "coldboot";
|
||||
|
||||
static ssize_t boot_mode_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", boot_mode);
|
||||
}
|
||||
|
||||
static struct kobj_attribute kobj_boot_mode = __ATTR_RO(boot_mode);
|
||||
|
||||
static int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
|
||||
const char *cmd)
|
||||
{
|
||||
@@ -49,23 +63,60 @@ static int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
|
||||
return magic;
|
||||
}
|
||||
|
||||
static int reboot_mode_notify(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
static void reboot_mode_write(struct reboot_mode_driver *reboot,
|
||||
const void *cmd)
|
||||
{
|
||||
struct reboot_mode_driver *reboot;
|
||||
int magic;
|
||||
|
||||
reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
|
||||
magic = get_reboot_mode_magic(reboot, cmd);
|
||||
if (!magic)
|
||||
magic = get_reboot_mode_magic(reboot, NULL);
|
||||
if (magic)
|
||||
reboot->write(magic);
|
||||
}
|
||||
|
||||
static int reboot_mode_notify(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
struct reboot_mode_driver *reboot;
|
||||
|
||||
reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
|
||||
reboot_mode_write(reboot, cmd);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
int reboot_mode_register(struct device *dev, int (*write)(int))
|
||||
static int reboot_mode_panic_notify(struct notifier_block *this,
|
||||
unsigned long ev, void *ptr)
|
||||
{
|
||||
struct reboot_mode_driver *reboot;
|
||||
const char *cmd = "panic";
|
||||
|
||||
reboot = container_of(this, struct reboot_mode_driver, panic_notifier);
|
||||
reboot_mode_write(reboot, cmd);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int boot_mode_parse(struct reboot_mode_driver *reboot)
|
||||
{
|
||||
struct mode_info *info;
|
||||
unsigned int magic = reboot->read();
|
||||
|
||||
list_for_each_entry(info, &reboot->head, list) {
|
||||
if (info->magic == magic) {
|
||||
boot_mode = info->mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("Boot mode: %s\n", boot_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reboot_mode_register(struct device *dev, int (*write)(int),
|
||||
int (*read)(void))
|
||||
{
|
||||
struct reboot_mode_driver *reboot;
|
||||
struct mode_info *info;
|
||||
@@ -78,6 +129,7 @@ int reboot_mode_register(struct device *dev, int (*write)(int))
|
||||
return -ENOMEM;
|
||||
|
||||
reboot->write = write;
|
||||
reboot->read = read;
|
||||
INIT_LIST_HEAD(&reboot->head);
|
||||
for_each_property_of_node(dev->of_node, prop) {
|
||||
if (len > strlen(prop->name) || strncmp(prop->name, PREFIX, len))
|
||||
@@ -94,10 +146,13 @@ int reboot_mode_register(struct device *dev, int (*write)(int))
|
||||
}
|
||||
list_add_tail(&info->list, &reboot->head);
|
||||
}
|
||||
boot_mode_parse(reboot);
|
||||
reboot->reboot_notifier.notifier_call = reboot_mode_notify;
|
||||
reboot->panic_notifier.notifier_call = reboot_mode_panic_notify;
|
||||
ret = register_reboot_notifier(&reboot->reboot_notifier);
|
||||
if (ret)
|
||||
dev_err(dev, "can't register reboot notifier\n");
|
||||
ret += atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&reboot->panic_notifier);
|
||||
ret += sysfs_create_file(kernel_kobj, &kobj_boot_mode.attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef __REBOOT_MODE_H__
|
||||
#define __REBOOT_MODE_H__
|
||||
|
||||
int reboot_mode_register(struct device *dev, int (*write)(int));
|
||||
int reboot_mode_register(struct device *dev, int (*write)(int),
|
||||
int (*read)(void));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,15 @@ static int syscon_reboot_mode_write(int magic)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int syscon_reboot_mode_read(void)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
regmap_read(map, offset, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int syscon_reboot_mode_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@@ -39,7 +48,8 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev)
|
||||
if (of_property_read_u32(pdev->dev.of_node, "offset", &offset))
|
||||
return -EINVAL;
|
||||
of_property_read_u32(pdev->dev.of_node, "mask", &mask);
|
||||
ret = reboot_mode_register(&pdev->dev, syscon_reboot_mode_write);
|
||||
ret = reboot_mode_register(&pdev->dev, syscon_reboot_mode_write,
|
||||
syscon_reboot_mode_read);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "can't register reboot mode\n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user