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