|
@@ -23,7 +23,66 @@
|
|
#define XO15_SCI_CLASS DRV_NAME
|
|
#define XO15_SCI_CLASS DRV_NAME
|
|
#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI"
|
|
#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI"
|
|
|
|
|
|
-static unsigned long xo15_sci_gpe;
|
|
|
|
|
|
+static unsigned long xo15_sci_gpe;
|
|
|
|
+static bool lid_wake_on_close;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * The normal ACPI LID wakeup behavior is wake-on-open, but not
|
|
|
|
+ * wake-on-close. This is implemented as standard by the XO-1.5 DSDT.
|
|
|
|
+ *
|
|
|
|
+ * We provide here a sysfs attribute that will additionally enable
|
|
|
|
+ * wake-on-close behavior. This is useful (e.g.) when we oportunistically
|
|
|
|
+ * suspend with the display running; if the lid is then closed, we want to
|
|
|
|
+ * wake up to turn the display off.
|
|
|
|
+ *
|
|
|
|
+ * This is controlled through a custom method in the XO-1.5 DSDT.
|
|
|
|
+ */
|
|
|
|
+static int set_lid_wake_behavior(bool wake_on_close)
|
|
|
|
+{
|
|
|
|
+ struct acpi_object_list arg_list;
|
|
|
|
+ union acpi_object arg;
|
|
|
|
+ acpi_status status;
|
|
|
|
+
|
|
|
|
+ arg_list.count = 1;
|
|
|
|
+ arg_list.pointer = &arg;
|
|
|
|
+ arg.type = ACPI_TYPE_INTEGER;
|
|
|
|
+ arg.integer.value = wake_on_close;
|
|
|
|
+
|
|
|
|
+ status = acpi_evaluate_object(NULL, "\\_SB.PCI0.LID.LIDW", &arg_list, NULL);
|
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
|
+ pr_warning(PFX "failed to set lid behavior\n");
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lid_wake_on_close = wake_on_close;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t
|
|
|
|
+lid_wake_on_close_show(struct kobject *s, struct kobj_attribute *attr, char *buf)
|
|
|
|
+{
|
|
|
|
+ return sprintf(buf, "%u\n", lid_wake_on_close);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t lid_wake_on_close_store(struct kobject *s,
|
|
|
|
+ struct kobj_attribute *attr,
|
|
|
|
+ const char *buf, size_t n)
|
|
|
|
+{
|
|
|
|
+ unsigned int val;
|
|
|
|
+
|
|
|
|
+ if (sscanf(buf, "%u", &val) != 1)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ set_lid_wake_behavior(!!val);
|
|
|
|
+
|
|
|
|
+ return n;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct kobj_attribute lid_wake_on_close_attr =
|
|
|
|
+ __ATTR(lid_wake_on_close, 0644,
|
|
|
|
+ lid_wake_on_close_show,
|
|
|
|
+ lid_wake_on_close_store);
|
|
|
|
|
|
static void battery_status_changed(void)
|
|
static void battery_status_changed(void)
|
|
{
|
|
{
|
|
@@ -91,6 +150,7 @@ static int xo15_sci_add(struct acpi_device *device)
|
|
{
|
|
{
|
|
unsigned long long tmp;
|
|
unsigned long long tmp;
|
|
acpi_status status;
|
|
acpi_status status;
|
|
|
|
+ int r;
|
|
|
|
|
|
if (!device)
|
|
if (!device)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -112,6 +172,10 @@ static int xo15_sci_add(struct acpi_device *device)
|
|
|
|
|
|
dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe);
|
|
dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe);
|
|
|
|
|
|
|
|
+ r = sysfs_create_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
|
|
|
|
+ if (r)
|
|
|
|
+ goto err_sysfs;
|
|
|
|
+
|
|
/* Flush queue, and enable all SCI events */
|
|
/* Flush queue, and enable all SCI events */
|
|
process_sci_queue();
|
|
process_sci_queue();
|
|
olpc_ec_mask_write(EC_SCI_SRC_ALL);
|
|
olpc_ec_mask_write(EC_SCI_SRC_ALL);
|
|
@@ -123,6 +187,11 @@ static int xo15_sci_add(struct acpi_device *device)
|
|
device_init_wakeup(&device->dev, true);
|
|
device_init_wakeup(&device->dev, true);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+err_sysfs:
|
|
|
|
+ acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
|
|
|
|
+ cancel_work_sync(&sci_work);
|
|
|
|
+ return r;
|
|
}
|
|
}
|
|
|
|
|
|
static int xo15_sci_remove(struct acpi_device *device, int type)
|
|
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)
|
|
acpi_disable_gpe(NULL, xo15_sci_gpe);
|
|
acpi_disable_gpe(NULL, xo15_sci_gpe);
|
|
acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
|
|
acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
|
|
cancel_work_sync(&sci_work);
|
|
cancel_work_sync(&sci_work);
|
|
|
|
+ sysfs_remove_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|