aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@srcf.ucam.org>2013-07-02 18:41:03 -0400
committerMatthew Garrett <matthew.garrett@nebula.com>2013-07-10 15:42:48 -0400
commit34a956db3774e8cba3f6b52aa9c1d67cf9a496fe (patch)
treefbc6a170ee548c9cf4a170bd6e399bfe5fd1f557
parent8667ca9518bbe0eff2222e69d611f4c8549fcbde (diff)
Add support driver for Intel Rapid Start Technology
Intel Rapid Start Technology is a firmware-based suspend-to-disk implementation. Once placed in S3, the device will wake once either a timeout elapses or the battery reaches a critical level. It will then resume to the firmware and copy the contents of RAM to a specialised partition, and then power off the machine. If the user turns the machine back on the firmware will copy the contents of the partition back to RAM and then resume from S3 as normal. This driver provides an interface for configuring the wakeup events and timeout. It still requires firmware support and an appropriate suspend partition. Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
-rw-r--r--Documentation/ABI/testing/sysfs-driver-intel-rapid-start21
-rw-r--r--drivers/platform/x86/Kconfig12
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/intel-rst.c209
4 files changed, 243 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-intel-rapid-start b/Documentation/ABI/testing/sysfs-driver-intel-rapid-start
new file mode 100644
index 000000000000..5a7d2e217d40
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-intel-rapid-start
@@ -0,0 +1,21 @@
1What: /sys/bus/acpi/intel-rapid-start/wakeup_events
2Date: July 2, 2013
3KernelVersion: 3.11
4Contact: Matthew Garrett <mjg59@srcf.ucam.org>
5Description: An integer representing a set of wakeup events as follows:
6 1: Wake to enter hibernation when the wakeup timer expires
7 2: Wake to enter hibernation when the battery reaches a
8 critical level
9
10 These values are ORed together. For example, a value of 3
11 indicates that the system will wake to enter hibernation when
12 either the wakeup timer expires or the battery reaches a
13 critical level.
14
15What: /sys/bus/acpi/intel-rapid-start/wakeup_time
16Date: July 2, 2013
17KernelVersion: 3.11
18Contact: Matthew Garrett <mjg59@srcf.ucam.org>
19Description: An integer representing the length of time the system will
20 remain asleep before waking up to enter hibernation.
21 This value is in minutes.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 37645b923c52..36057f481162 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -782,6 +782,18 @@ config APPLE_GMUX
782 graphics as well as the backlight. Currently only backlight 782 graphics as well as the backlight. Currently only backlight
783 control is supported by the driver. 783 control is supported by the driver.
784 784
785config INTEL_RST
786 tristate "Intel Rapid Start Technology Driver"
787 depends on ACPI
788 ---help---
789 This driver provides support for modifying paramaters on systems
790 equipped with Intel's Rapid Start Technology. When put in an ACPI
791 sleep state, these devices will wake after either a configured
792 timeout or when the system battery reaches a critical state,
793 automatically copying memory contents to disk. On resume, the
794 firmware will copy the memory contents back to RAM and resume the OS
795 as usual.
796
785config PVPANIC 797config PVPANIC
786 tristate "pvpanic device support" 798 tristate "pvpanic device support"
787 depends on ACPI 799 depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index ef0ec746f78c..5c669ce8d243 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
51obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 51obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
52obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o 52obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
53obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 53obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
54obj-$(CONFIG_INTEL_RST) += intel-rst.o
54 55
55obj-$(CONFIG_PVPANIC) += pvpanic.o 56obj-$(CONFIG_PVPANIC) += pvpanic.o
diff --git a/drivers/platform/x86/intel-rst.c b/drivers/platform/x86/intel-rst.c
new file mode 100644
index 000000000000..9385afd9b558
--- /dev/null
+++ b/drivers/platform/x86/intel-rst.c
@@ -0,0 +1,209 @@
1/*
2 * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <acpi/acpi_drivers.h>
24
25MODULE_LICENSE("GPL");
26
27static ssize_t irst_show_wakeup_events(struct device *dev,
28 struct device_attribute *attr,
29 char *buf)
30{
31 struct acpi_device *acpi;
32 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
33 union acpi_object *result;
34 acpi_status status;
35
36 acpi = to_acpi_device(dev);
37
38 status = acpi_evaluate_object(acpi->handle, "GFFS", NULL, &output);
39 if (!ACPI_SUCCESS(status))
40 return -EINVAL;
41
42 result = output.pointer;
43
44 if (result->type != ACPI_TYPE_INTEGER) {
45 kfree(result);
46 return -EINVAL;
47 }
48
49 return sprintf(buf, "%lld\n", result->integer.value);
50}
51
52static ssize_t irst_store_wakeup_events(struct device *dev,
53 struct device_attribute *attr,
54 const char *buf, size_t count)
55{
56 struct acpi_device *acpi;
57 struct acpi_object_list input;
58 union acpi_object param;
59 acpi_status status;
60 unsigned long value;
61 int error;
62
63 acpi = to_acpi_device(dev);
64
65 error = kstrtoul(buf, 0, &value);
66
67 if (error)
68 return error;
69
70 param.type = ACPI_TYPE_INTEGER;
71 param.integer.value = value;
72
73 input.count = 1;
74 input.pointer = &param;
75
76 status = acpi_evaluate_object(acpi->handle, "SFFS", &input, NULL);
77
78 if (!ACPI_SUCCESS(status))
79 return -EINVAL;
80
81 return count;
82}
83
84static struct device_attribute irst_wakeup_attr = {
85 .attr = { .name = "wakeup_events", .mode = 0600 },
86 .show = irst_show_wakeup_events,
87 .store = irst_store_wakeup_events
88};
89
90static ssize_t irst_show_wakeup_time(struct device *dev,
91 struct device_attribute *attr, char *buf)
92{
93 struct acpi_device *acpi;
94 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
95 union acpi_object *result;
96 acpi_status status;
97
98 acpi = to_acpi_device(dev);
99
100 status = acpi_evaluate_object(acpi->handle, "GFTV", NULL, &output);
101 if (!ACPI_SUCCESS(status))
102 return -EINVAL;
103
104 result = output.pointer;
105
106 if (result->type != ACPI_TYPE_INTEGER) {
107 kfree(result);
108 return -EINVAL;
109 }
110
111 return sprintf(buf, "%lld\n", result->integer.value);
112}
113
114static ssize_t irst_store_wakeup_time(struct device *dev,
115 struct device_attribute *attr,
116 const char *buf, size_t count)
117{
118 struct acpi_device *acpi;
119 struct acpi_object_list input;
120 union acpi_object param;
121 acpi_status status;
122 unsigned long value;
123 int error;
124
125 acpi = to_acpi_device(dev);
126
127 error = kstrtoul(buf, 0, &value);
128
129 if (error)
130 return error;
131
132 param.type = ACPI_TYPE_INTEGER;
133 param.integer.value = value;
134
135 input.count = 1;
136 input.pointer = &param;
137
138 status = acpi_evaluate_object(acpi->handle, "SFTV", &input, NULL);
139
140 if (!ACPI_SUCCESS(status))
141 return -EINVAL;
142
143 return count;
144}
145
146static struct device_attribute irst_timeout_attr = {
147 .attr = { .name = "wakeup_time", .mode = 0600 },
148 .show = irst_show_wakeup_time,
149 .store = irst_store_wakeup_time
150};
151
152static int irst_add(struct acpi_device *acpi)
153{
154 int error = 0;
155
156 error = device_create_file(&acpi->dev, &irst_timeout_attr);
157 if (error)
158 goto out;
159
160 error = device_create_file(&acpi->dev, &irst_wakeup_attr);
161 if (error)
162 goto out_timeout;
163
164 return 0;
165
166out_timeout:
167 device_remove_file(&acpi->dev, &irst_timeout_attr);
168out:
169 return error;
170}
171
172static int irst_remove(struct acpi_device *acpi)
173{
174 device_remove_file(&acpi->dev, &irst_wakeup_attr);
175 device_remove_file(&acpi->dev, &irst_timeout_attr);
176
177 return 0;
178}
179
180static const struct acpi_device_id irst_ids[] = {
181 {"INT3392", 0},
182 {"", 0}
183};
184
185static struct acpi_driver irst_driver = {
186 .owner = THIS_MODULE,
187 .name = "intel_rapid_start",
188 .class = "intel_rapid_start",
189 .ids = irst_ids,
190 .ops = {
191 .add = irst_add,
192 .remove = irst_remove,
193 },
194};
195
196static int irst_init(void)
197{
198 return acpi_bus_register_driver(&irst_driver);
199}
200
201static void irst_exit(void)
202{
203 acpi_bus_unregister_driver(&irst_driver);
204}
205
206module_init(irst_init);
207module_exit(irst_exit);
208
209MODULE_DEVICE_TABLE(acpi, irst_ids);