1e6596c22SKate Hsuan // SPDX-License-Identifier: GPL-2.0+
2e6596c22SKate Hsuan /*
3e6596c22SKate Hsuan * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
4e6596c22SKate Hsuan */
5e6596c22SKate Hsuan
6e6596c22SKate Hsuan #include <linux/acpi.h>
7e6596c22SKate Hsuan #include <linux/module.h>
8e6596c22SKate Hsuan #include <linux/slab.h>
9e6596c22SKate Hsuan
10e6596c22SKate Hsuan MODULE_LICENSE("GPL");
11e6596c22SKate Hsuan
irst_show_wakeup_events(struct device * dev,struct device_attribute * attr,char * buf)12e6596c22SKate Hsuan static ssize_t irst_show_wakeup_events(struct device *dev,
13e6596c22SKate Hsuan struct device_attribute *attr,
14e6596c22SKate Hsuan char *buf)
15e6596c22SKate Hsuan {
16e6596c22SKate Hsuan struct acpi_device *acpi;
17e6596c22SKate Hsuan unsigned long long value;
18e6596c22SKate Hsuan acpi_status status;
19e6596c22SKate Hsuan
20e6596c22SKate Hsuan acpi = to_acpi_device(dev);
21e6596c22SKate Hsuan
22e6596c22SKate Hsuan status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value);
23e6596c22SKate Hsuan if (ACPI_FAILURE(status))
24e6596c22SKate Hsuan return -EINVAL;
25e6596c22SKate Hsuan
26e6596c22SKate Hsuan return sprintf(buf, "%lld\n", value);
27e6596c22SKate Hsuan }
28e6596c22SKate Hsuan
irst_store_wakeup_events(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)29e6596c22SKate Hsuan static ssize_t irst_store_wakeup_events(struct device *dev,
30e6596c22SKate Hsuan struct device_attribute *attr,
31e6596c22SKate Hsuan const char *buf, size_t count)
32e6596c22SKate Hsuan {
33e6596c22SKate Hsuan struct acpi_device *acpi;
34e6596c22SKate Hsuan acpi_status status;
35e6596c22SKate Hsuan unsigned long value;
36e6596c22SKate Hsuan int error;
37e6596c22SKate Hsuan
38e6596c22SKate Hsuan acpi = to_acpi_device(dev);
39e6596c22SKate Hsuan
40e6596c22SKate Hsuan error = kstrtoul(buf, 0, &value);
41e6596c22SKate Hsuan if (error)
42e6596c22SKate Hsuan return error;
43e6596c22SKate Hsuan
44e6596c22SKate Hsuan status = acpi_execute_simple_method(acpi->handle, "SFFS", value);
45e6596c22SKate Hsuan if (ACPI_FAILURE(status))
46e6596c22SKate Hsuan return -EINVAL;
47e6596c22SKate Hsuan
48e6596c22SKate Hsuan return count;
49e6596c22SKate Hsuan }
50e6596c22SKate Hsuan
51e6596c22SKate Hsuan static struct device_attribute irst_wakeup_attr = {
52e6596c22SKate Hsuan .attr = { .name = "wakeup_events", .mode = 0600 },
53e6596c22SKate Hsuan .show = irst_show_wakeup_events,
54e6596c22SKate Hsuan .store = irst_store_wakeup_events
55e6596c22SKate Hsuan };
56e6596c22SKate Hsuan
irst_show_wakeup_time(struct device * dev,struct device_attribute * attr,char * buf)57e6596c22SKate Hsuan static ssize_t irst_show_wakeup_time(struct device *dev,
58e6596c22SKate Hsuan struct device_attribute *attr, char *buf)
59e6596c22SKate Hsuan {
60e6596c22SKate Hsuan struct acpi_device *acpi;
61e6596c22SKate Hsuan unsigned long long value;
62e6596c22SKate Hsuan acpi_status status;
63e6596c22SKate Hsuan
64e6596c22SKate Hsuan acpi = to_acpi_device(dev);
65e6596c22SKate Hsuan
66e6596c22SKate Hsuan status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value);
67e6596c22SKate Hsuan if (ACPI_FAILURE(status))
68e6596c22SKate Hsuan return -EINVAL;
69e6596c22SKate Hsuan
70e6596c22SKate Hsuan return sprintf(buf, "%lld\n", value);
71e6596c22SKate Hsuan }
72e6596c22SKate Hsuan
irst_store_wakeup_time(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)73e6596c22SKate Hsuan static ssize_t irst_store_wakeup_time(struct device *dev,
74e6596c22SKate Hsuan struct device_attribute *attr,
75e6596c22SKate Hsuan const char *buf, size_t count)
76e6596c22SKate Hsuan {
77e6596c22SKate Hsuan struct acpi_device *acpi;
78e6596c22SKate Hsuan acpi_status status;
79e6596c22SKate Hsuan unsigned long value;
80e6596c22SKate Hsuan int error;
81e6596c22SKate Hsuan
82e6596c22SKate Hsuan acpi = to_acpi_device(dev);
83e6596c22SKate Hsuan
84e6596c22SKate Hsuan error = kstrtoul(buf, 0, &value);
85e6596c22SKate Hsuan if (error)
86e6596c22SKate Hsuan return error;
87e6596c22SKate Hsuan
88e6596c22SKate Hsuan status = acpi_execute_simple_method(acpi->handle, "SFTV", value);
89e6596c22SKate Hsuan if (ACPI_FAILURE(status))
90e6596c22SKate Hsuan return -EINVAL;
91e6596c22SKate Hsuan
92e6596c22SKate Hsuan return count;
93e6596c22SKate Hsuan }
94e6596c22SKate Hsuan
95e6596c22SKate Hsuan static struct device_attribute irst_timeout_attr = {
96e6596c22SKate Hsuan .attr = { .name = "wakeup_time", .mode = 0600 },
97e6596c22SKate Hsuan .show = irst_show_wakeup_time,
98e6596c22SKate Hsuan .store = irst_store_wakeup_time
99e6596c22SKate Hsuan };
100e6596c22SKate Hsuan
irst_add(struct acpi_device * acpi)101e6596c22SKate Hsuan static int irst_add(struct acpi_device *acpi)
102e6596c22SKate Hsuan {
103e6596c22SKate Hsuan int error;
104e6596c22SKate Hsuan
105e6596c22SKate Hsuan error = device_create_file(&acpi->dev, &irst_timeout_attr);
106e6596c22SKate Hsuan if (unlikely(error))
107e6596c22SKate Hsuan return error;
108e6596c22SKate Hsuan
109e6596c22SKate Hsuan error = device_create_file(&acpi->dev, &irst_wakeup_attr);
110e6596c22SKate Hsuan if (unlikely(error))
111e6596c22SKate Hsuan device_remove_file(&acpi->dev, &irst_timeout_attr);
112e6596c22SKate Hsuan
113e6596c22SKate Hsuan return error;
114e6596c22SKate Hsuan }
115e6596c22SKate Hsuan
irst_remove(struct acpi_device * acpi)116*6c0eb5baSDawei Li static void irst_remove(struct acpi_device *acpi)
117e6596c22SKate Hsuan {
118e6596c22SKate Hsuan device_remove_file(&acpi->dev, &irst_wakeup_attr);
119e6596c22SKate Hsuan device_remove_file(&acpi->dev, &irst_timeout_attr);
120e6596c22SKate Hsuan }
121e6596c22SKate Hsuan
122e6596c22SKate Hsuan static const struct acpi_device_id irst_ids[] = {
123e6596c22SKate Hsuan {"INT3392", 0},
124e6596c22SKate Hsuan {"", 0}
125e6596c22SKate Hsuan };
126e6596c22SKate Hsuan
127e6596c22SKate Hsuan static struct acpi_driver irst_driver = {
128e6596c22SKate Hsuan .owner = THIS_MODULE,
129e6596c22SKate Hsuan .name = "intel_rapid_start",
130e6596c22SKate Hsuan .class = "intel_rapid_start",
131e6596c22SKate Hsuan .ids = irst_ids,
132e6596c22SKate Hsuan .ops = {
133e6596c22SKate Hsuan .add = irst_add,
134e6596c22SKate Hsuan .remove = irst_remove,
135e6596c22SKate Hsuan },
136e6596c22SKate Hsuan };
137e6596c22SKate Hsuan
138e6596c22SKate Hsuan module_acpi_driver(irst_driver);
139e6596c22SKate Hsuan
140e6596c22SKate Hsuan MODULE_DEVICE_TABLE(acpi, irst_ids);
141