summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeepak Saxena <dsaxena@laptop.org>2008-07-30 14:06:06 -0700
committerDeepak Saxena <dsaxena@laptop.org>2008-08-01 00:49:44 -0700
commita347731f82edeb8f176ae0bcfcc5d7fee6786a7c (patch)
treec83259decea156a6d9179c921f0343891ef649fe
parent4cb5af5103d70b9989d5e520fc869e9c0669df2b (diff)
downloadlwn-a347731f82edeb8f176ae0bcfcc5d7fee6786a7c.tar.gz
lwn-a347731f82edeb8f176ae0bcfcc5d7fee6786a7c.zip
Re-implement lid state detect code
As per OLPC trac #5703 and #7536, this patch re-implements the lid detection code to only wake up on lid open when we are suspended and to use the readback of the lid GPIO to determine the system state. Signed-off-by: Deepak Saxena <dsaxena@laptop.org>
-rw-r--r--arch/x86/kernel/olpc-pm.c67
1 files changed, 31 insertions, 36 deletions
diff --git a/arch/x86/kernel/olpc-pm.c b/arch/x86/kernel/olpc-pm.c
index 5ce12267da8c..aff66aa53bcb 100644
--- a/arch/x86/kernel/olpc-pm.c
+++ b/arch/x86/kernel/olpc-pm.c
@@ -57,7 +57,6 @@ static int olpc_pm_mode = PM_MODE_NORMAL;
static unsigned long acpi_base;
static unsigned long pms_base;
static int sci_irq;
-static int olpc_lid_flag;
static struct input_dev *pm_inputdev;
static struct input_dev *lid_inputdev;
@@ -235,40 +234,37 @@ static int olpc_pm_interrupt(int irq, void *id)
schedule_work(&sci_work);
}
+ /*
+ * See http://dev.laptop.org/ticket/5703 for details
+ * on why we do what we do below, specifically the udelay().
+ */
if (gpe & GPIO_WAKEUP_LID) {
- /* Disable events */
geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
-
- /* Clear the edge */
-
- if (olpc_lid_flag)
- geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
- else
- geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
-
- /* Clear the status too */
- geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
- geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
+
+ if (geode_gpio_isset(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS)) {
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
+ }
- /* The line is high when the LID is open, but SW_LID
- * should be high when the LID is closed, so we pass the old
- * value of olpc_lid_flag
- */
+ if (geode_gpio_isset(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS)) {
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
+ }
+
+ geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
+ geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
+
+ udelay(100);
+
+ input_report_switch(lid_inputdev, SW_LID,
+ !geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK));
- input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag);
input_sync(lid_inputdev);
+
if (!wackup_source)
wackup_source = "lid";
- /* Swap the status */
- olpc_lid_flag = !olpc_lid_flag;
-
- if (olpc_lid_flag)
- geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
- else
- geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
-
- /* re-enable the event */
+ /* Re-enable both events */
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
}
@@ -415,7 +411,12 @@ int olpc_fixup_sleep(void)
else
olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN);
+ /*
+ * We only want to wakeup on lid open, not on lid close
+ */
if (device_may_wakeup(&olpc_lid_dev.dev)) {
+ geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
gpio_wake_events |= GPIO_WAKEUP_LID;
} else {
@@ -893,15 +894,9 @@ static int __init olpc_pm_init(void)
if (olpc_board_at_least(olpc_board(0xb2))) {
gpio_wake_events |= GPIO_WAKEUP_LID;
- /* Get the current value of the GPIO, and set up the edges */
- olpc_lid_flag = geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK);
-
- /* Watch for the opposite edge */
-
- if (olpc_lid_flag)
- geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
- else
- geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
+ /* Watch for both edges at startup */
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
+ geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
/* Enable the event */
geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);