summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-03-16 08:51:01 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-03-20 05:36:04 -0400
commit95c513ec84f7ff35cd9d8c7ce4a99f770bd82c3b (patch)
tree8bc974278c3d0d7118a49ca1253f29b1912e53a4
parentc698ca5278934c0ae32297a8725ced2e27585d7f (diff)
ACPI: Add Time and Alarm Device (TAD) driver
Introduce a driver for the ACPI Time and Alarm Device (TAD) based on Section 9.18 of ACPI 6.2. This driver only supports the system wakeup capabilities of the TAD which are mandatory. Support for the RTC capabilities of the TAD will be added to it in the future. This driver is entirely sysfs-based. It provides attributes (under the TAD platform device) to allow user space to manage the AC and DC wakeup timers of the TAD: set and read their values, set and check their expire timer wake policies, check and clear their status and check the capabilities of the TAD reported by AML. The DC timer attributes are only present if the TAD supports a separate DC alarm timer. The wakeup events handling and power management of the TAD is expected to be taken care of by the ACPI PM domain attached to its platform device. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD113
-rw-r--r--drivers/acpi/Kconfig13
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_tad.c473
4 files changed, 600 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD b/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD
new file mode 100644
index 000000000000..7e43cdce9a52
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD
@@ -0,0 +1,113 @@
1 ACPI Time and Alarm (TAD) device attributes.
2
3What: /sys/bus/platform/devices/ACPI000E:00/caps
4Date: March 2018
5Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
6Description:
7 (RO) Hexadecimal bitmask of the TAD attributes are reported by
8 the platform firmware (see ACPI 6.2, section 9.18.2):
9
10 BIT(0): AC wakeup implemented if set
11 BIT(1): DC wakeup implemented if set
12 BIT(2): Get/set real time features implemented if set
13 BIT(3): Real time accuracy in milliseconds if set
14 BIT(4): Correct status reported for wakeups from S4/S5 if set
15 BIT(5): The AC timer wakes up from S4 if set
16 BIT(6): The AC timer wakes up from S5 if set
17 BIT(7): The DC timer wakes up from S4 if set
18 BIT(8): The DC timer wakes up from S5 if set
19
20 The other bits are reserved.
21
22What: /sys/bus/platform/devices/ACPI000E:00/ac_alarm
23Date: March 2018
24Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
25Description:
26 (RW) The AC alarm timer value.
27
28 Reads return the current AC alarm timer value in seconds or
29 "disabled", if the AC alarm is not set to wake up the system.
30
31 Write a new AC alarm timer value in seconds or "disabled" to it
32 to set the AC alarm timer or to disable it, respectively.
33
34 If the AC alarm timer is set through this attribute and it
35 expires, it will immediately wake up the system from the S3
36 sleep state (and from S4/S5 too if supported) until its status
37 is explicitly cleared via the ac_status attribute.
38
39What: /sys/bus/platform/devices/ACPI000E:00/ac_policy
40Date: March 2018
41Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
42Description:
43 (RW) The AC alarm expired timer wake policy (see ACPI 6.2,
44 Section 9.18 for details).
45
46 Reads return the current expired timer wake delay for the AC
47 alarm timer or "never", if the policy is to discard AC timer
48 wakeups if the system is on DC power.
49
50 Write a new expired timer wake delay for the AC alarm timer in
51 seconds or "never" to it to set the expired timer wake delay for
52 the AC alarm timer or to set its expired wake policy to discard
53 wakeups if the system is on DC power, respectively.
54
55What: /sys/bus/platform/devices/ACPI000E:00/ac_status
56Date: March 2018
57Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
58Description:
59 (RW) The AC alarm status.
60
61 Reads return a hexadecimal bitmask representing the AC alarm
62 timer status with the following meaning of bits (see ACPI 6.2,
63 Section 9.18.5):
64
65 Bit(0): The timer has expired if set.
66 Bit(1): The timer has woken up the system from a sleep state
67 (S3 or S4/S5 if supported) if set.
68
69 The other bits are reserved.
70
71 Reads also cause the AC alarm timer status to be reset.
72
73 Another way to reset the the status of the AC alarm timer is to
74 write (the number) 0 to this file.
75
76 If the status return value indicates that the timer has expired,
77 it will immediately wake up the system from the S3 sleep state
78 (and from S4/S5 too if supported) until its status is explicitly
79 cleared through this attribute.
80
81What: /sys/bus/platform/devices/ACPI000E:00/dc_alarm
82Date: March 2018
83Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
84Description:
85 (RW,optional) The DC alarm timer value.
86
87 This attribute is only present if the TAD supports a separate
88 DC timer.
89
90 It is analogous to the ac_alarm attribute.
91
92What: /sys/bus/platform/devices/ACPI000E:00/dc_policy
93Date: March 2018
94Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
95Description:
96 (RW,optional) The DC alarm expired timer wake policy.
97
98 This attribute is only present if the TAD supports a separate
99 DC timer.
100
101 It is analogous to the ac_policy attribute.
102
103What: /sys/bus/platform/devices/ACPI000E:00/dc_status
104Date: March 2018
105Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
106
107Description:
108 (RW,optional) The DC alarm status.
109
110 This attribute is only present if the TAD supports a separate
111 DC timer.
112
113 It is analogous to the ac_status attribute.
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index f505e9a01b2d..7cea52ab4418 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -217,6 +217,19 @@ config ACPI_FAN
217 To compile this driver as a module, choose M here: 217 To compile this driver as a module, choose M here:
218 the module will be called fan. 218 the module will be called fan.
219 219
220config ACPI_TAD
221 tristate "ACPI Time and Alarm (TAD) Device Support"
222 depends on SYSFS && PM_SLEEP
223 help
224 The ACPI Time and Alarm (TAD) device is an alternative to the Real
225 Time Clock (RTC). Its wake timers allow the system to transition from
226 the S3 (or optionally S4/S5) state to S0 state after a time period
227 elapses. In comparison with the RTC Alarm, the TAD provides a larger
228 scale of flexibility in the wake timers. The time capabilities of the
229 TAD maintain the time of day information across platform power
230 transitions, and keep track of time even when the platform is turned
231 off.
232
220config ACPI_DOCK 233config ACPI_DOCK
221 bool "Dock" 234 bool "Dock"
222 help 235 help
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 41954a601989..48e202752754 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_AC) += ac.o
70obj-$(CONFIG_ACPI_BUTTON) += button.o 70obj-$(CONFIG_ACPI_BUTTON) += button.o
71obj-$(CONFIG_ACPI_FAN) += fan.o 71obj-$(CONFIG_ACPI_FAN) += fan.o
72obj-$(CONFIG_ACPI_VIDEO) += video.o 72obj-$(CONFIG_ACPI_VIDEO) += video.o
73obj-$(CONFIG_ACPI_TAD) += acpi_tad.o
73obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o 74obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
74obj-$(CONFIG_ACPI_PROCESSOR) += processor.o 75obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
75obj-$(CONFIG_ACPI) += container.o 76obj-$(CONFIG_ACPI) += container.o
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
new file mode 100644
index 000000000000..e99c4ed7e677
--- /dev/null
+++ b/drivers/acpi/acpi_tad.c
@@ -0,0 +1,473 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ACPI Time and Alarm (TAD) Device Driver
4 *
5 * Copyright (C) 2018 Intel Corporation
6 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
7 *
8 * This driver is based on Section 9.18 of the ACPI 6.2 specification revision.
9 *
10 * It only supports the system wakeup capabilities of the TAD.
11 *
12 * Provided are sysfs attributes, available under the TAD platform device,
13 * allowing user space to manage the AC and DC wakeup timers of the TAD:
14 * set and read their values, set and check their expire timer wake policies,
15 * check and clear their status and check the capabilities of the TAD reported
16 * by AML. The DC timer attributes are only present if the TAD supports a
17 * separate DC alarm timer.
18 *
19 * The wakeup events handling and power management of the TAD is expected to
20 * be taken care of by the ACPI PM domain attached to its platform device.
21 */
22
23#include <linux/acpi.h>
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
28#include <linux/suspend.h>
29
30MODULE_LICENSE("GPL v2");
31MODULE_AUTHOR("Rafael J. Wysocki");
32
33/* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */
34#define ACPI_TAD_AC_WAKE BIT(0)
35#define ACPI_TAD_DC_WAKE BIT(1)
36#define ACPI_TAD_RT BIT(2)
37#define ACPI_TAD_RT_IN_MS BIT(3)
38#define ACPI_TAD_S4_S5__GWS BIT(4)
39#define ACPI_TAD_AC_S4_WAKE BIT(5)
40#define ACPI_TAD_AC_S5_WAKE BIT(6)
41#define ACPI_TAD_DC_S4_WAKE BIT(7)
42#define ACPI_TAD_DC_S5_WAKE BIT(8)
43
44/* ACPI TAD alarm timer selection */
45#define ACPI_TAD_AC_TIMER (u32)0
46#define ACPI_TAD_DC_TIMER (u32)1
47
48/* Special value for disabled timer or expired timer wake policy. */
49#define ACPI_TAD_WAKE_DISABLED (~(u32)0)
50
51struct acpi_tad_driver_data {
52 u32 capabilities;
53};
54
55static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
56 u32 value)
57{
58 acpi_handle handle = ACPI_HANDLE(dev);
59 union acpi_object args[] = {
60 { .type = ACPI_TYPE_INTEGER, },
61 { .type = ACPI_TYPE_INTEGER, },
62 };
63 struct acpi_object_list arg_list = {
64 .pointer = args,
65 .count = ARRAY_SIZE(args),
66 };
67 unsigned long long retval;
68 acpi_status status;
69
70 args[0].integer.value = timer_id;
71 args[1].integer.value = value;
72
73 pm_runtime_get_sync(dev);
74
75 status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
76
77 pm_runtime_put_sync(dev);
78
79 if (ACPI_FAILURE(status) || retval)
80 return -EIO;
81
82 return 0;
83}
84
85static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method,
86 u32 timer_id, const char *specval)
87{
88 u32 value;
89
90 if (sysfs_streq(buf, specval)) {
91 value = ACPI_TAD_WAKE_DISABLED;
92 } else {
93 int ret = kstrtou32(buf, 0, &value);
94
95 if (ret)
96 return ret;
97
98 if (value == ACPI_TAD_WAKE_DISABLED)
99 return -EINVAL;
100 }
101
102 return acpi_tad_wake_set(dev, method, timer_id, value);
103}
104
105static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method,
106 u32 timer_id, const char *specval)
107{
108 acpi_handle handle = ACPI_HANDLE(dev);
109 union acpi_object args[] = {
110 { .type = ACPI_TYPE_INTEGER, },
111 };
112 struct acpi_object_list arg_list = {
113 .pointer = args,
114 .count = ARRAY_SIZE(args),
115 };
116 unsigned long long retval;
117 acpi_status status;
118
119 args[0].integer.value = timer_id;
120
121 pm_runtime_get_sync(dev);
122
123 status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
124
125 pm_runtime_put_sync(dev);
126
127 if (ACPI_FAILURE(status))
128 return -EIO;
129
130 if ((u32)retval == ACPI_TAD_WAKE_DISABLED)
131 return sprintf(buf, "%s\n", specval);
132
133 return sprintf(buf, "%u\n", (u32)retval);
134}
135
136static const char *alarm_specval = "disabled";
137
138static int acpi_tad_alarm_write(struct device *dev, const char *buf,
139 u32 timer_id)
140{
141 return acpi_tad_wake_write(dev, buf, "_STV", timer_id, alarm_specval);
142}
143
144static ssize_t acpi_tad_alarm_read(struct device *dev, char *buf, u32 timer_id)
145{
146 return acpi_tad_wake_read(dev, buf, "_TIV", timer_id, alarm_specval);
147}
148
149static const char *policy_specval = "never";
150
151static int acpi_tad_policy_write(struct device *dev, const char *buf,
152 u32 timer_id)
153{
154 return acpi_tad_wake_write(dev, buf, "_STP", timer_id, policy_specval);
155}
156
157static ssize_t acpi_tad_policy_read(struct device *dev, char *buf, u32 timer_id)
158{
159 return acpi_tad_wake_read(dev, buf, "_TIP", timer_id, policy_specval);
160}
161
162static int acpi_tad_clear_status(struct device *dev, u32 timer_id)
163{
164 acpi_handle handle = ACPI_HANDLE(dev);
165 union acpi_object args[] = {
166 { .type = ACPI_TYPE_INTEGER, },
167 };
168 struct acpi_object_list arg_list = {
169 .pointer = args,
170 .count = ARRAY_SIZE(args),
171 };
172 unsigned long long retval;
173 acpi_status status;
174
175 args[0].integer.value = timer_id;
176
177 pm_runtime_get_sync(dev);
178
179 status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval);
180
181 pm_runtime_put_sync(dev);
182
183 if (ACPI_FAILURE(status) || retval)
184 return -EIO;
185
186 return 0;
187}
188
189static int acpi_tad_status_write(struct device *dev, const char *buf, u32 timer_id)
190{
191 int ret, value;
192
193 ret = kstrtoint(buf, 0, &value);
194 if (ret)
195 return ret;
196
197 if (value)
198 return -EINVAL;
199
200 return acpi_tad_clear_status(dev, timer_id);
201}
202
203static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id)
204{
205 acpi_handle handle = ACPI_HANDLE(dev);
206 union acpi_object args[] = {
207 { .type = ACPI_TYPE_INTEGER, },
208 };
209 struct acpi_object_list arg_list = {
210 .pointer = args,
211 .count = ARRAY_SIZE(args),
212 };
213 unsigned long long retval;
214 acpi_status status;
215
216 args[0].integer.value = timer_id;
217
218 pm_runtime_get_sync(dev);
219
220 status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval);
221
222 pm_runtime_put_sync(dev);
223
224 if (ACPI_FAILURE(status))
225 return -EIO;
226
227 return sprintf(buf, "0x%02X\n", (u32)retval);
228}
229
230static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
231 char *buf)
232{
233 struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
234
235 return sprintf(buf, "0x%02X\n", dd->capabilities);
236}
237
238static DEVICE_ATTR_RO(caps);
239
240static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr,
241 const char *buf, size_t count)
242{
243 int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_AC_TIMER);
244
245 return ret ? ret : count;
246}
247
248static ssize_t ac_alarm_show(struct device *dev, struct device_attribute *attr,
249 char *buf)
250{
251 return acpi_tad_alarm_read(dev, buf, ACPI_TAD_AC_TIMER);
252}
253
254static DEVICE_ATTR(ac_alarm, S_IRUSR | S_IWUSR, ac_alarm_show, ac_alarm_store);
255
256static ssize_t ac_policy_store(struct device *dev, struct device_attribute *attr,
257 const char *buf, size_t count)
258{
259 int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_AC_TIMER);
260
261 return ret ? ret : count;
262}
263
264static ssize_t ac_policy_show(struct device *dev, struct device_attribute *attr,
265 char *buf)
266{
267 return acpi_tad_policy_read(dev, buf, ACPI_TAD_AC_TIMER);
268}
269
270static DEVICE_ATTR(ac_policy, S_IRUSR | S_IWUSR, ac_policy_show, ac_policy_store);
271
272static ssize_t ac_status_store(struct device *dev, struct device_attribute *attr,
273 const char *buf, size_t count)
274{
275 int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_AC_TIMER);
276
277 return ret ? ret : count;
278}
279
280static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr,
281 char *buf)
282{
283 return acpi_tad_status_read(dev, buf, ACPI_TAD_AC_TIMER);
284}
285
286static DEVICE_ATTR(ac_status, S_IRUSR | S_IWUSR, ac_status_show, ac_status_store);
287
288static struct attribute *acpi_tad_attrs[] = {
289 &dev_attr_caps.attr,
290 &dev_attr_ac_alarm.attr,
291 &dev_attr_ac_policy.attr,
292 &dev_attr_ac_status.attr,
293 NULL,
294};
295static const struct attribute_group acpi_tad_attr_group = {
296 .attrs = acpi_tad_attrs,
297};
298
299static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr,
300 const char *buf, size_t count)
301{
302 int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_DC_TIMER);
303
304 return ret ? ret : count;
305}
306
307static ssize_t dc_alarm_show(struct device *dev, struct device_attribute *attr,
308 char *buf)
309{
310 return acpi_tad_alarm_read(dev, buf, ACPI_TAD_DC_TIMER);
311}
312
313static DEVICE_ATTR(dc_alarm, S_IRUSR | S_IWUSR, dc_alarm_show, dc_alarm_store);
314
315static ssize_t dc_policy_store(struct device *dev, struct device_attribute *attr,
316 const char *buf, size_t count)
317{
318 int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_DC_TIMER);
319
320 return ret ? ret : count;
321}
322
323static ssize_t dc_policy_show(struct device *dev, struct device_attribute *attr,
324 char *buf)
325{
326 return acpi_tad_policy_read(dev, buf, ACPI_TAD_DC_TIMER);
327}
328
329static DEVICE_ATTR(dc_policy, S_IRUSR | S_IWUSR, dc_policy_show, dc_policy_store);
330
331static ssize_t dc_status_store(struct device *dev, struct device_attribute *attr,
332 const char *buf, size_t count)
333{
334 int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_DC_TIMER);
335
336 return ret ? ret : count;
337}
338
339static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr,
340 char *buf)
341{
342 return acpi_tad_status_read(dev, buf, ACPI_TAD_DC_TIMER);
343}
344
345static DEVICE_ATTR(dc_status, S_IRUSR | S_IWUSR, dc_status_show, dc_status_store);
346
347static struct attribute *acpi_tad_dc_attrs[] = {
348 &dev_attr_dc_alarm.attr,
349 &dev_attr_dc_policy.attr,
350 &dev_attr_dc_status.attr,
351 NULL,
352};
353static const struct attribute_group acpi_tad_dc_attr_group = {
354 .attrs = acpi_tad_dc_attrs,
355};
356
357static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
358{
359 return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
360}
361
362static int acpi_tad_remove(struct platform_device *pdev)
363{
364 struct device *dev = &pdev->dev;
365 struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
366
367 device_init_wakeup(dev, false);
368
369 pm_runtime_get_sync(dev);
370
371 if (dd->capabilities & ACPI_TAD_DC_WAKE)
372 sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group);
373
374 sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
375
376 acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
377 acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
378 if (dd->capabilities & ACPI_TAD_DC_WAKE) {
379 acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
380 acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
381 }
382
383 pm_runtime_put_sync(dev);
384 pm_runtime_disable(dev);
385 return 0;
386}
387
388static int acpi_tad_probe(struct platform_device *pdev)
389{
390 struct device *dev = &pdev->dev;
391 acpi_handle handle = ACPI_HANDLE(dev);
392 struct acpi_tad_driver_data *dd;
393 acpi_status status;
394 unsigned long long caps;
395 int ret;
396
397 /*
398 * Initialization failure messages are mostly about firmware issues, so
399 * print them at the "info" level.
400 */
401 status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps);
402 if (ACPI_FAILURE(status)) {
403 dev_info(dev, "Unable to get capabilities\n");
404 return -ENODEV;
405 }
406
407 if (!(caps & ACPI_TAD_AC_WAKE)) {
408 dev_info(dev, "Unsupported capabilities\n");
409 return -ENODEV;
410 }
411
412 if (!acpi_has_method(handle, "_PRW")) {
413 dev_info(dev, "Missing _PRW\n");
414 return -ENODEV;
415 }
416
417 dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
418 if (!dd)
419 return -ENOMEM;
420
421 dd->capabilities = caps;
422 dev_set_drvdata(dev, dd);
423
424 /*
425 * Assume that the ACPI PM domain has been attached to the device and
426 * simply enable system wakeup and runtime PM and put the device into
427 * runtime suspend. Everything else should be taken care of by the ACPI
428 * PM domain callbacks.
429 */
430 device_init_wakeup(dev, true);
431 dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
432 DPM_FLAG_LEAVE_SUSPENDED);
433 /*
434 * The platform bus type layer tells the ACPI PM domain powers up the
435 * device, so set the runtime PM status of it to "active".
436 */
437 pm_runtime_set_active(dev);
438 pm_runtime_enable(dev);
439 pm_runtime_suspend(dev);
440
441 ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
442 if (ret)
443 goto fail;
444
445 if (caps & ACPI_TAD_DC_WAKE) {
446 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
447 if (ret)
448 goto fail;
449 }
450
451 return 0;
452
453fail:
454 acpi_tad_remove(pdev);
455 return ret;
456}
457
458static const struct acpi_device_id acpi_tad_ids[] = {
459 {"ACPI000E", 0},
460 {}
461};
462
463static struct platform_driver acpi_tad_driver = {
464 .driver = {
465 .name = "acpi-tad",
466 .acpi_match_table = acpi_tad_ids,
467 },
468 .probe = acpi_tad_probe,
469 .remove = acpi_tad_remove,
470};
471MODULE_DEVICE_TABLE(acpi, acpi_tad_ids);
472
473module_platform_driver(acpi_tad_driver);