CHROMIUM: mfd: chromeos_ec: suspend/resume fixes
authorOlof Johansson <olofj@chromium.org>
Sat, 21 Jul 2012 22:29:24 +0000 (15:29 -0700)
committerGerrit <chrome-bot@google.com>
Sun, 22 Jul 2012 00:44:02 +0000 (17:44 -0700)
If IRQs are left on, one will fire before the rest of the system is up
enough to process it if there has been a pending keypress. So we need to
disable interrupts across suspend/resume.

Also, enable wake source, and register the pm event.

BUG=chrome-os-partner:11625
TEST=powerd_suspend + wake from keyboard

Change-Id: I9996f766ffd1c49f7e45ba8f76f273884151d593
Signed-off-by: Olof Johansson <olofj@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/28127
Reviewed-by: Benson Leung <bleung@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
drivers/mfd/chromeos_ec.c
include/linux/mfd/chromeos_ec.h

index f5ba20a..cef1526 100644 (file)
 
 #define COMMAND_MAX_TRIES 3
 
+static inline struct chromeos_ec_device *to_ec_dev(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return i2c_get_clientdata(client);
+}
+
 static int cros_ec_command_xfer_noretry(struct chromeos_ec_device *ec_dev,
                                        struct chromeos_ec_msg *msg)
 {
@@ -148,7 +154,7 @@ static int cros_ec_command_xfer(struct chromeos_ec_device *ec_dev,
                if (ret >= 0)
                        return ret;
        }
-       dev_err(ec_dev->dev, "mkbp_command failed with %d (%d tries)\n",
+       dev_err(ec_dev->dev, "ec_command failed with %d (%d tries)\n",
                ret, tries);
        return ret;
 }
@@ -191,6 +197,9 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
 {
        struct chromeos_ec_device *ec = data;
 
+       if (device_may_wakeup(ec->dev))
+               pm_wakeup_event(ec->dev, 0);
+
        blocking_notifier_call_chain(&ec->event_notifier, 1, ec);
 
        return IRQ_HANDLED;
@@ -285,11 +294,27 @@ fail:
 #ifdef CONFIG_PM_SLEEP
 static int cros_ec_suspend(struct device *dev)
 {
+       struct chromeos_ec_device *ec = to_ec_dev(dev);
+
+       if (device_may_wakeup(dev))
+               ec->wake_enabled = !enable_irq_wake(ec->irq);
+
+       disable_irq(ec->irq);
+
        return 0;
 }
 
 static int cros_ec_resume(struct device *dev)
 {
+       struct chromeos_ec_device *ec = to_ec_dev(dev);
+
+       enable_irq(ec->irq);
+
+       if (ec->wake_enabled) {
+               disable_irq_wake(ec->irq);
+               ec->wake_enabled = 0;
+       }
+
        return 0;
 }
 #endif
index 989713b..34c0980 100644 (file)
@@ -36,6 +36,7 @@ struct chromeos_ec_device {
        struct device *dev;
        struct i2c_client *client;
        int irq;
+       bool wake_enabled;
        struct blocking_notifier_head event_notifier;
        int (*command_send)(struct chromeos_ec_device *ec,
                        char cmd, void *out_buf, int out_len);