aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/platform/olpc/olpc-xo15-sci.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index 2b235b77d9ab..23e5b9d7977b 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -23,7 +23,66 @@
23#define XO15_SCI_CLASS DRV_NAME 23#define XO15_SCI_CLASS DRV_NAME
24#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI" 24#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI"
25 25
26static unsigned long xo15_sci_gpe; 26static unsigned long xo15_sci_gpe;
27static bool lid_wake_on_close;
28
29/*
30 * The normal ACPI LID wakeup behavior is wake-on-open, but not
31 * wake-on-close. This is implemented as standard by the XO-1.5 DSDT.
32 *
33 * We provide here a sysfs attribute that will additionally enable
34 * wake-on-close behavior. This is useful (e.g.) when we oportunistically
35 * suspend with the display running; if the lid is then closed, we want to
36 * wake up to turn the display off.
37 *
38 * This is controlled through a custom method in the XO-1.5 DSDT.
39 */
40static int set_lid_wake_behavior(bool wake_on_close)
41{
42 struct acpi_object_list arg_list;
43 union acpi_object arg;
44 acpi_status status;
45
46 arg_list.count = 1;
47 arg_list.pointer = &arg;
48 arg.type = ACPI_TYPE_INTEGER;
49 arg.integer.value = wake_on_close;
50
51 status = acpi_evaluate_object(NULL, "\\_SB.PCI0.LID.LIDW", &arg_list, NULL);
52 if (ACPI_FAILURE(status)) {
53 pr_warning(PFX "failed to set lid behavior\n");
54 return 1;
55 }
56
57 lid_wake_on_close = wake_on_close;
58
59 return 0;
60}
61
62static ssize_t
63lid_wake_on_close_show(struct kobject *s, struct kobj_attribute *attr, char *buf)
64{
65 return sprintf(buf, "%u\n", lid_wake_on_close);
66}
67
68static ssize_t lid_wake_on_close_store(struct kobject *s,
69 struct kobj_attribute *attr,
70 const char *buf, size_t n)
71{
72 unsigned int val;
73
74 if (sscanf(buf, "%u", &val) != 1)
75 return -EINVAL;
76
77 set_lid_wake_behavior(!!val);
78
79 return n;
80}
81
82static struct kobj_attribute lid_wake_on_close_attr =
83 __ATTR(lid_wake_on_close, 0644,
84 lid_wake_on_close_show,
85 lid_wake_on_close_store);
27 86
28static void battery_status_changed(void) 87static void battery_status_changed(void)
29{ 88{
@@ -91,6 +150,7 @@ static int xo15_sci_add(struct acpi_device *device)
91{ 150{
92 unsigned long long tmp; 151 unsigned long long tmp;
93 acpi_status status; 152 acpi_status status;
153 int r;
94 154
95 if (!device) 155 if (!device)
96 return -EINVAL; 156 return -EINVAL;
@@ -112,6 +172,10 @@ static int xo15_sci_add(struct acpi_device *device)
112 172
113 dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe); 173 dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe);
114 174
175 r = sysfs_create_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
176 if (r)
177 goto err_sysfs;
178
115 /* Flush queue, and enable all SCI events */ 179 /* Flush queue, and enable all SCI events */
116 process_sci_queue(); 180 process_sci_queue();
117 olpc_ec_mask_write(EC_SCI_SRC_ALL); 181 olpc_ec_mask_write(EC_SCI_SRC_ALL);
@@ -123,6 +187,11 @@ static int xo15_sci_add(struct acpi_device *device)
123 device_init_wakeup(&device->dev, true); 187 device_init_wakeup(&device->dev, true);
124 188
125 return 0; 189 return 0;
190
191err_sysfs:
192 acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
193 cancel_work_sync(&sci_work);
194 return r;
126} 195}
127 196
128static int xo15_sci_remove(struct acpi_device *device, int type) 197static int xo15_sci_remove(struct acpi_device *device, int type)
@@ -130,6 +199,7 @@ static int xo15_sci_remove(struct acpi_device *device, int type)
130 acpi_disable_gpe(NULL, xo15_sci_gpe); 199 acpi_disable_gpe(NULL, xo15_sci_gpe);
131 acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler); 200 acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
132 cancel_work_sync(&sci_work); 201 cancel_work_sync(&sci_work);
202 sysfs_remove_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
133 return 0; 203 return 0;
134} 204}
135 205