From: huangjun huangjun63@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@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);