diff options
-rw-r--r-- | drivers/input/touchscreen/wm97xx-core.c | 56 | ||||
-rw-r--r-- | include/linux/wm97xx.h | 3 |
2 files changed, 51 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 2910999e05a0..e9c7ea46b6e3 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c | |||
@@ -262,6 +262,23 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir, | |||
262 | EXPORT_SYMBOL_GPL(wm97xx_config_gpio); | 262 | EXPORT_SYMBOL_GPL(wm97xx_config_gpio); |
263 | 263 | ||
264 | /* | 264 | /* |
265 | * Configure the WM97XX_PRP value to use while system is suspended. | ||
266 | * If a value other than 0 is set then WM97xx pen detection will be | ||
267 | * left enabled in the configured mode while the system is in suspend, | ||
268 | * the device has users and suspend has not been disabled via the | ||
269 | * wakeup sysfs entries. | ||
270 | * | ||
271 | * @wm: WM97xx device to configure | ||
272 | * @mode: WM97XX_PRP value to configure while suspended | ||
273 | */ | ||
274 | void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode) | ||
275 | { | ||
276 | wm->suspend_mode = mode; | ||
277 | device_init_wakeup(&wm->input_dev->dev, mode != 0); | ||
278 | } | ||
279 | EXPORT_SYMBOL_GPL(wm97xx_set_suspend_mode); | ||
280 | |||
281 | /* | ||
265 | * Handle a pen down interrupt. | 282 | * Handle a pen down interrupt. |
266 | */ | 283 | */ |
267 | static void wm97xx_pen_irq_worker(struct work_struct *work) | 284 | static void wm97xx_pen_irq_worker(struct work_struct *work) |
@@ -328,18 +345,18 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) | |||
328 | * | 345 | * |
329 | * We have to disable the codec interrupt in the handler because it | 346 | * We have to disable the codec interrupt in the handler because it |
330 | * can take upto 1ms to clear the interrupt source. We schedule a task | 347 | * can take upto 1ms to clear the interrupt source. We schedule a task |
331 | * in a work queue to do the actual interaction with the chip (it | 348 | * in a work queue to do the actual interaction with the chip. The |
332 | * doesn't matter if we end up reenqueing it before it is executed | 349 | * interrupt is then enabled again in the slow handler when the source |
333 | * since we don't touch the chip until it has run). The interrupt is | 350 | * has been cleared. |
334 | * then enabled again in the slow handler when the source has been | ||
335 | * cleared. | ||
336 | */ | 351 | */ |
337 | static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) | 352 | static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) |
338 | { | 353 | { |
339 | struct wm97xx *wm = dev_id; | 354 | struct wm97xx *wm = dev_id; |
340 | 355 | ||
341 | wm->mach_ops->irq_enable(wm, 0); | 356 | if (!work_pending(&wm->pen_event_work)) { |
342 | queue_work(wm->ts_workq, &wm->pen_event_work); | 357 | wm->mach_ops->irq_enable(wm, 0); |
358 | queue_work(wm->ts_workq, &wm->pen_event_work); | ||
359 | } | ||
343 | 360 | ||
344 | return IRQ_HANDLED; | 361 | return IRQ_HANDLED; |
345 | } | 362 | } |
@@ -355,7 +372,8 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm) | |||
355 | * provided. */ | 372 | * provided. */ |
356 | BUG_ON(!wm->mach_ops->irq_enable); | 373 | BUG_ON(!wm->mach_ops->irq_enable); |
357 | 374 | ||
358 | if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, | 375 | if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, |
376 | IRQF_SHARED | IRQF_SAMPLE_RANDOM, | ||
359 | "wm97xx-pen", wm)) { | 377 | "wm97xx-pen", wm)) { |
360 | dev_err(wm->dev, | 378 | dev_err(wm->dev, |
361 | "Failed to register pen down interrupt, polling"); | 379 | "Failed to register pen down interrupt, polling"); |
@@ -688,10 +706,32 @@ static int wm97xx_remove(struct device *dev) | |||
688 | static int wm97xx_suspend(struct device *dev, pm_message_t state) | 706 | static int wm97xx_suspend(struct device *dev, pm_message_t state) |
689 | { | 707 | { |
690 | struct wm97xx *wm = dev_get_drvdata(dev); | 708 | struct wm97xx *wm = dev_get_drvdata(dev); |
709 | u16 reg; | ||
710 | int suspend_mode; | ||
711 | |||
712 | if (device_may_wakeup(&wm->input_dev->dev)) | ||
713 | suspend_mode = wm->suspend_mode; | ||
714 | else | ||
715 | suspend_mode = 0; | ||
691 | 716 | ||
692 | if (wm->input_dev->users) | 717 | if (wm->input_dev->users) |
693 | cancel_delayed_work_sync(&wm->ts_reader); | 718 | cancel_delayed_work_sync(&wm->ts_reader); |
694 | 719 | ||
720 | /* Power down the digitiser (bypassing the cache for resume) */ | ||
721 | reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2); | ||
722 | reg &= ~WM97XX_PRP_DET_DIG; | ||
723 | if (wm->input_dev->users) | ||
724 | reg |= suspend_mode; | ||
725 | wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg); | ||
726 | |||
727 | /* WM9713 has an additional power bit - turn it off if there | ||
728 | * are no users or if suspend mode is zero. */ | ||
729 | if (wm->id == WM9713_ID2 && | ||
730 | (!wm->input_dev->users || !suspend_mode)) { | ||
731 | reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000; | ||
732 | wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); | ||
733 | } | ||
734 | |||
695 | return 0; | 735 | return 0; |
696 | } | 736 | } |
697 | 737 | ||
diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h index ed01c7df54a3..4d13732e9cf0 100644 --- a/include/linux/wm97xx.h +++ b/include/linux/wm97xx.h | |||
@@ -282,6 +282,7 @@ struct wm97xx { | |||
282 | unsigned pen_is_down:1; /* Pen is down */ | 282 | unsigned pen_is_down:1; /* Pen is down */ |
283 | unsigned aux_waiting:1; /* aux measurement waiting */ | 283 | unsigned aux_waiting:1; /* aux measurement waiting */ |
284 | unsigned pen_probably_down:1; /* used in polling mode */ | 284 | unsigned pen_probably_down:1; /* used in polling mode */ |
285 | u16 suspend_mode; /* PRP in suspend mode */ | ||
285 | }; | 286 | }; |
286 | 287 | ||
287 | /* | 288 | /* |
@@ -297,6 +298,8 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, | |||
297 | enum wm97xx_gpio_sticky sticky, | 298 | enum wm97xx_gpio_sticky sticky, |
298 | enum wm97xx_gpio_wake wake); | 299 | enum wm97xx_gpio_wake wake); |
299 | 300 | ||
301 | void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode); | ||
302 | |||
300 | /* codec AC97 IO access */ | 303 | /* codec AC97 IO access */ |
301 | int wm97xx_reg_read(struct wm97xx *wm, u16 reg); | 304 | int wm97xx_reg_read(struct wm97xx *wm, u16 reg); |
302 | void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val); | 305 | void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val); |