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