diff options
author | Deepak Saxena <dsaxena@laptop.org> | 2008-07-30 14:06:06 -0700 |
---|---|---|
committer | Deepak Saxena <dsaxena@laptop.org> | 2008-08-01 00:49:44 -0700 |
commit | a347731f82edeb8f176ae0bcfcc5d7fee6786a7c (patch) | |
tree | c83259decea156a6d9179c921f0343891ef649fe | |
parent | 4cb5af5103d70b9989d5e520fc869e9c0669df2b (diff) | |
download | lwn-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.c | 67 |
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); |