From: huangjun <huangjun63(a)huawei.com>
If we want acpi ged to support wake from freeze, we need to implement
the suspend/resume function. In these two methods, ACPI's _GPO, GPP
method is called to realize the setting of sleep flag and anti-shake.
Signed-off-by: Huangjun <huangjun63(a)huawei.com>
---
drivers/acpi/evged.c | 82 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c
index f13ba2c07667..84656fc09d15 100644
--- a/drivers/acpi/evged.c
+++ b/drivers/acpi/evged.c
@@ -46,11 +46,14 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#define MODULE_NAME "acpi-ged"
struct acpi_ged_device {
struct device *dev;
+ struct timer_list timer;
struct list_head event_list;
};
@@ -148,6 +151,8 @@ static int ged_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "unable to parse the _CRS record\n");
return -EINVAL;
}
+
+ timer_setup(&geddev->timer, NULL, 0);
platform_set_drvdata(pdev, geddev);
return 0;
@@ -164,6 +169,7 @@ static void ged_shutdown(struct platform_device *pdev)
dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n",
event->gsi, event->irq);
}
+ del_timer(&geddev->timer);
}
static int ged_remove(struct platform_device *pdev)
@@ -177,6 +183,78 @@ static const struct acpi_device_id ged_acpi_ids[] = {
{},
};
+#ifdef CONFIG_PM_SLEEP
+static acpi_status ged_acpi_execute(struct device *dev, char* method, u64 arg)
+{
+ acpi_status acpi_ret;
+ acpi_handle method_handle;
+
+ acpi_ret = acpi_get_handle(ACPI_HANDLE(dev), method, &method_handle);
+
+ if (ACPI_FAILURE(acpi_ret)) {
+ dev_err(dev, "cannot locate %s method\n", method);
+ return AE_NOT_FOUND;
+ }
+
+ acpi_ret = acpi_execute_simple_method(method_handle, NULL, arg);
+ if (ACPI_FAILURE(acpi_ret)) {
+ dev_err(dev, "%s method execution failed\n", method);
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+static void ged_timer_callback(struct timer_list *t)
+{
+ struct acpi_ged_device *geddev = from_timer(geddev, t, timer);
+ struct acpi_ged_event *event, *next;
+
+ list_for_each_entry_safe(event, next, &geddev->event_list, node) {
+ ged_acpi_execute(geddev->dev, "_GPP", event->gsi);
+ }
+}
+
+static int ged_suspend(struct device *dev)
+{
+ struct acpi_ged_device *geddev = dev_get_drvdata(dev);
+ struct acpi_ged_event *event, *next;
+ acpi_status acpi_ret;
+
+ list_for_each_entry_safe(event, next, &geddev->event_list, node) {
+ acpi_ret = ged_acpi_execute(dev, "_GPO", event->gsi);
+
+ if (acpi_ret == AE_ERROR)
+ return -EINVAL;
+
+ enable_irq_wake(event->irq);
+ }
+ return 0;
+}
+
+static int ged_resume(struct device *dev)
+{
+ struct acpi_ged_device *geddev = dev_get_drvdata(dev);
+ struct acpi_ged_event *event, *next;
+
+ list_for_each_entry_safe(event, next, &geddev->event_list, node) {
+ disable_irq_wake(event->irq);
+ }
+
+ /* use timer to complete 4s anti-shake */
+ geddev->timer.expires = jiffies + (4 * HZ);
+ geddev->timer.function = ged_timer_callback;
+ add_timer(&geddev->timer);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ged_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ged_suspend, ged_resume)
+};
+#endif
+
+
static struct platform_driver ged_driver = {
.probe = ged_probe,
.remove = ged_remove,
@@ -184,6 +262,10 @@ static struct platform_driver ged_driver = {
.driver = {
.name = MODULE_NAME,
.acpi_match_table = ACPI_PTR(ged_acpi_ids),
+#ifdef CONFIG_PM_SLEEP
+ .pm = &ged_pm_ops,
+#endif
+
},
};
builtin_platform_driver(ged_driver);
--
2.20.1