Input: wm97xx-core - support use as a wakeup source
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 17 Apr 2008 13:24:58 +0000 (09:24 -0400)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 17 Apr 2008 13:24:58 +0000 (09:24 -0400)
The WM97xx touch screen controllers can be used to generate a wakeup
event when the system is suspended. Provide a new core API call
wm97xx_set_suspend_mode() allowing machine drivers to enable this. If no
suspend_mode is provided then the touch panel will be powered down when
the system is suspended.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/touchscreen/wm97xx-core.c
include/linux/wm97xx.h

index fec07c28281a72789fdc4b6aa68e785449b51760..e9c7ea46b6e30e1f1fc6b0881e16f8606245907a 100644 (file)
@@ -261,6 +261,23 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
 }
 EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
 
+/*
+ * Configure the WM97XX_PRP value to use while system is suspended.
+ * If a value other than 0 is set then WM97xx pen detection will be
+ * left enabled in the configured mode while the system is in suspend,
+ * the device has users and suspend has not been disabled via the
+ * wakeup sysfs entries.
+ *
+ * @wm:   WM97xx device to configure
+ * @mode: WM97XX_PRP value to configure while suspended
+ */
+void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode)
+{
+       wm->suspend_mode = mode;
+       device_init_wakeup(&wm->input_dev->dev, mode != 0);
+}
+EXPORT_SYMBOL_GPL(wm97xx_set_suspend_mode);
+
 /*
  * Handle a pen down interrupt.
  */
@@ -689,10 +706,32 @@ static int wm97xx_remove(struct device *dev)
 static int wm97xx_suspend(struct device *dev, pm_message_t state)
 {
        struct wm97xx *wm = dev_get_drvdata(dev);
+       u16 reg;
+       int suspend_mode;
+
+       if (device_may_wakeup(&wm->input_dev->dev))
+               suspend_mode = wm->suspend_mode;
+       else
+               suspend_mode = 0;
 
        if (wm->input_dev->users)
                cancel_delayed_work_sync(&wm->ts_reader);
 
+       /* Power down the digitiser (bypassing the cache for resume) */
+       reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2);
+       reg &= ~WM97XX_PRP_DET_DIG;
+       if (wm->input_dev->users)
+               reg |= suspend_mode;
+       wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg);
+
+       /* WM9713 has an additional power bit - turn it off if there
+        * are no users or if suspend mode is zero. */
+       if (wm->id == WM9713_ID2 &&
+           (!wm->input_dev->users || !suspend_mode)) {
+               reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000;
+               wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
+       }
+
        return 0;
 }
 
index ed01c7df54a30c9b5ab9638f942aba57dd295ff9..4d13732e9cf0dceda29c869b2d165aa810c5f719 100644 (file)
@@ -282,6 +282,7 @@ struct wm97xx {
        unsigned pen_is_down:1;         /* Pen is down */
        unsigned aux_waiting:1;         /* aux measurement waiting */
        unsigned pen_probably_down:1;   /* used in polling mode */
+       u16 suspend_mode;               /* PRP in suspend mode */
 };
 
 /*
@@ -297,6 +298,8 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio,
                                     enum wm97xx_gpio_sticky sticky,
                                     enum wm97xx_gpio_wake wake);
 
+void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode);
+
 /* codec AC97 IO access */
 int wm97xx_reg_read(struct wm97xx *wm, u16 reg);
 void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val);