aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRakesh Iyer <riyer@nvidia.com>2011-09-08 18:34:11 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-09-09 12:25:42 -0400
commitd0d150ec28ab05eb2ec8cf9fcb7c9753ec95e0d4 (patch)
tree9031f750dadb8f8ba82190295755dde351c8ddc0
parent9299c08d8bfc7256645f4bf3943f80d8943fe844 (diff)
Input: tegra-kbc - fix wakeup from suspend
For wakeup to be reliable, kbc needs to be in interrupt mode before suspend. Created common routine to control the FIFO interrupt. Added synchronization to ensure orderly suspend. Signed-off-by: Rakesh Iyer <riyer@nvidia.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/keyboard/tegra-kbc.c58
1 files changed, 43 insertions, 15 deletions
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index a5a77915c650..8fb474f03940 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -55,6 +55,7 @@
55 55
56#define KBC_ROW_CFG0_0 0x8 56#define KBC_ROW_CFG0_0 0x8
57#define KBC_COL_CFG0_0 0x18 57#define KBC_COL_CFG0_0 0x18
58#define KBC_TO_CNT_0 0x24
58#define KBC_INIT_DLY_0 0x28 59#define KBC_INIT_DLY_0 0x28
59#define KBC_RPT_DLY_0 0x2c 60#define KBC_RPT_DLY_0 0x2c
60#define KBC_KP_ENT0_0 0x30 61#define KBC_KP_ENT0_0 0x30
@@ -70,6 +71,7 @@ struct tegra_kbc {
70 spinlock_t lock; 71 spinlock_t lock;
71 unsigned int repoll_dly; 72 unsigned int repoll_dly;
72 unsigned long cp_dly_jiffies; 73 unsigned long cp_dly_jiffies;
74 unsigned int cp_to_wkup_dly;
73 bool use_fn_map; 75 bool use_fn_map;
74 bool use_ghost_filter; 76 bool use_ghost_filter;
75 const struct tegra_kbc_platform_data *pdata; 77 const struct tegra_kbc_platform_data *pdata;
@@ -341,6 +343,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
341 kbc->num_pressed_keys = num_down; 343 kbc->num_pressed_keys = num_down;
342} 344}
343 345
346static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
347{
348 u32 val;
349
350 val = readl(kbc->mmio + KBC_CONTROL_0);
351 if (enable)
352 val |= KBC_CONTROL_FIFO_CNT_INT_EN;
353 else
354 val &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
355 writel(val, kbc->mmio + KBC_CONTROL_0);
356}
357
344static void tegra_kbc_keypress_timer(unsigned long data) 358static void tegra_kbc_keypress_timer(unsigned long data)
345{ 359{
346 struct tegra_kbc *kbc = (struct tegra_kbc *)data; 360 struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@@ -370,9 +384,7 @@ static void tegra_kbc_keypress_timer(unsigned long data)
370 384
371 /* All keys are released so enable the keypress interrupt */ 385 /* All keys are released so enable the keypress interrupt */
372 spin_lock_irqsave(&kbc->lock, flags); 386 spin_lock_irqsave(&kbc->lock, flags);
373 val = readl(kbc->mmio + KBC_CONTROL_0); 387 tegra_kbc_set_fifo_interrupt(kbc, true);
374 val |= KBC_CONTROL_FIFO_CNT_INT_EN;
375 writel(val, kbc->mmio + KBC_CONTROL_0);
376 spin_unlock_irqrestore(&kbc->lock, flags); 388 spin_unlock_irqrestore(&kbc->lock, flags);
377 } 389 }
378} 390}
@@ -380,15 +392,13 @@ static void tegra_kbc_keypress_timer(unsigned long data)
380static irqreturn_t tegra_kbc_isr(int irq, void *args) 392static irqreturn_t tegra_kbc_isr(int irq, void *args)
381{ 393{
382 struct tegra_kbc *kbc = args; 394 struct tegra_kbc *kbc = args;
383 u32 val, ctl; 395 u32 val;
384 396
385 /* 397 /*
386 * Until all keys are released, defer further processing to 398 * Until all keys are released, defer further processing to
387 * the polling loop in tegra_kbc_keypress_timer 399 * the polling loop in tegra_kbc_keypress_timer
388 */ 400 */
389 ctl = readl(kbc->mmio + KBC_CONTROL_0); 401 tegra_kbc_set_fifo_interrupt(kbc, false);
390 ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
391 writel(ctl, kbc->mmio + KBC_CONTROL_0);
392 402
393 /* 403 /*
394 * Quickly bail out & reenable interrupts if the fifo threshold 404 * Quickly bail out & reenable interrupts if the fifo threshold
@@ -404,8 +414,7 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
404 */ 414 */
405 mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); 415 mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
406 } else { 416 } else {
407 ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; 417 tegra_kbc_set_fifo_interrupt(kbc, true);
408 writel(ctl, kbc->mmio + KBC_CONTROL_0);
409 } 418 }
410 419
411 return IRQ_HANDLED; 420 return IRQ_HANDLED;
@@ -734,18 +743,30 @@ static int tegra_kbc_suspend(struct device *dev)
734 struct platform_device *pdev = to_platform_device(dev); 743 struct platform_device *pdev = to_platform_device(dev);
735 struct tegra_kbc *kbc = platform_get_drvdata(pdev); 744 struct tegra_kbc *kbc = platform_get_drvdata(pdev);
736 745
746 mutex_lock(&kbc->idev->mutex);
737 if (device_may_wakeup(&pdev->dev)) { 747 if (device_may_wakeup(&pdev->dev)) {
738 tegra_kbc_setup_wakekeys(kbc, true); 748 disable_irq(kbc->irq);
739 enable_irq_wake(kbc->irq); 749 del_timer_sync(&kbc->timer);
750 tegra_kbc_set_fifo_interrupt(kbc, false);
751
740 /* Forcefully clear the interrupt status */ 752 /* Forcefully clear the interrupt status */
741 writel(0x7, kbc->mmio + KBC_INT_0); 753 writel(0x7, kbc->mmio + KBC_INT_0);
754 /*
755 * Store the previous resident time of continuous polling mode.
756 * Force the keyboard into interrupt mode.
757 */
758 kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0);
759 writel(0, kbc->mmio + KBC_TO_CNT_0);
760
761 tegra_kbc_setup_wakekeys(kbc, true);
742 msleep(30); 762 msleep(30);
763
764 enable_irq_wake(kbc->irq);
743 } else { 765 } else {
744 mutex_lock(&kbc->idev->mutex);
745 if (kbc->idev->users) 766 if (kbc->idev->users)
746 tegra_kbc_stop(kbc); 767 tegra_kbc_stop(kbc);
747 mutex_unlock(&kbc->idev->mutex);
748 } 768 }
769 mutex_unlock(&kbc->idev->mutex);
749 770
750 return 0; 771 return 0;
751} 772}
@@ -756,15 +777,22 @@ static int tegra_kbc_resume(struct device *dev)
756 struct tegra_kbc *kbc = platform_get_drvdata(pdev); 777 struct tegra_kbc *kbc = platform_get_drvdata(pdev);
757 int err = 0; 778 int err = 0;
758 779
780 mutex_lock(&kbc->idev->mutex);
759 if (device_may_wakeup(&pdev->dev)) { 781 if (device_may_wakeup(&pdev->dev)) {
760 disable_irq_wake(kbc->irq); 782 disable_irq_wake(kbc->irq);
761 tegra_kbc_setup_wakekeys(kbc, false); 783 tegra_kbc_setup_wakekeys(kbc, false);
784
785 /* Restore the resident time of continuous polling mode. */
786 writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
787
788 tegra_kbc_set_fifo_interrupt(kbc, true);
789
790 enable_irq(kbc->irq);
762 } else { 791 } else {
763 mutex_lock(&kbc->idev->mutex);
764 if (kbc->idev->users) 792 if (kbc->idev->users)
765 err = tegra_kbc_start(kbc); 793 err = tegra_kbc_start(kbc);
766 mutex_unlock(&kbc->idev->mutex);
767 } 794 }
795 mutex_unlock(&kbc->idev->mutex);
768 796
769 return err; 797 return err;
770} 798}