diff options
-rw-r--r-- | arch/x86/platform/olpc/olpc-xo15-sci.c | 72 |
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 | ||
26 | static unsigned long xo15_sci_gpe; | 26 | static unsigned long xo15_sci_gpe; |
27 | static 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 | */ | ||
40 | static 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 | |||
62 | static ssize_t | ||
63 | lid_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 | |||
68 | static 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 | |||
82 | static 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 | ||
28 | static void battery_status_changed(void) | 87 | static 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 | |||
191 | err_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 | ||
128 | static int xo15_sci_remove(struct acpi_device *device, int type) | 197 | static 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 | ||