Commit d0d150ec authored by Rakesh Iyer's avatar Rakesh Iyer Committed by Dmitry Torokhov

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: default avatarRakesh Iyer <riyer@nvidia.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 9299c08d
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#define KBC_ROW_CFG0_0 0x8 #define KBC_ROW_CFG0_0 0x8
#define KBC_COL_CFG0_0 0x18 #define KBC_COL_CFG0_0 0x18
#define KBC_TO_CNT_0 0x24
#define KBC_INIT_DLY_0 0x28 #define KBC_INIT_DLY_0 0x28
#define KBC_RPT_DLY_0 0x2c #define KBC_RPT_DLY_0 0x2c
#define KBC_KP_ENT0_0 0x30 #define KBC_KP_ENT0_0 0x30
...@@ -70,6 +71,7 @@ struct tegra_kbc { ...@@ -70,6 +71,7 @@ struct tegra_kbc {
spinlock_t lock; spinlock_t lock;
unsigned int repoll_dly; unsigned int repoll_dly;
unsigned long cp_dly_jiffies; unsigned long cp_dly_jiffies;
unsigned int cp_to_wkup_dly;
bool use_fn_map; bool use_fn_map;
bool use_ghost_filter; bool use_ghost_filter;
const struct tegra_kbc_platform_data *pdata; const struct tegra_kbc_platform_data *pdata;
...@@ -341,6 +343,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) ...@@ -341,6 +343,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
kbc->num_pressed_keys = num_down; kbc->num_pressed_keys = num_down;
} }
static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
{
u32 val;
val = readl(kbc->mmio + KBC_CONTROL_0);
if (enable)
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
else
val &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
writel(val, kbc->mmio + KBC_CONTROL_0);
}
static void tegra_kbc_keypress_timer(unsigned long data) static void tegra_kbc_keypress_timer(unsigned long data)
{ {
struct tegra_kbc *kbc = (struct tegra_kbc *)data; struct tegra_kbc *kbc = (struct tegra_kbc *)data;
...@@ -370,9 +384,7 @@ static void tegra_kbc_keypress_timer(unsigned long data) ...@@ -370,9 +384,7 @@ static void tegra_kbc_keypress_timer(unsigned long data)
/* All keys are released so enable the keypress interrupt */ /* All keys are released so enable the keypress interrupt */
spin_lock_irqsave(&kbc->lock, flags); spin_lock_irqsave(&kbc->lock, flags);
val = readl(kbc->mmio + KBC_CONTROL_0); tegra_kbc_set_fifo_interrupt(kbc, true);
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
writel(val, kbc->mmio + KBC_CONTROL_0);
spin_unlock_irqrestore(&kbc->lock, flags); spin_unlock_irqrestore(&kbc->lock, flags);
} }
} }
...@@ -380,15 +392,13 @@ static void tegra_kbc_keypress_timer(unsigned long data) ...@@ -380,15 +392,13 @@ static void tegra_kbc_keypress_timer(unsigned long data)
static irqreturn_t tegra_kbc_isr(int irq, void *args) static irqreturn_t tegra_kbc_isr(int irq, void *args)
{ {
struct tegra_kbc *kbc = args; struct tegra_kbc *kbc = args;
u32 val, ctl; u32 val;
/* /*
* Until all keys are released, defer further processing to * Until all keys are released, defer further processing to
* the polling loop in tegra_kbc_keypress_timer * the polling loop in tegra_kbc_keypress_timer
*/ */
ctl = readl(kbc->mmio + KBC_CONTROL_0); tegra_kbc_set_fifo_interrupt(kbc, false);
ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
writel(ctl, kbc->mmio + KBC_CONTROL_0);
/* /*
* Quickly bail out & reenable interrupts if the fifo threshold * Quickly bail out & reenable interrupts if the fifo threshold
...@@ -404,8 +414,7 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) ...@@ -404,8 +414,7 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
*/ */
mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
} else { } else {
ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; tegra_kbc_set_fifo_interrupt(kbc, true);
writel(ctl, kbc->mmio + KBC_CONTROL_0);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -734,18 +743,30 @@ static int tegra_kbc_suspend(struct device *dev) ...@@ -734,18 +743,30 @@ static int tegra_kbc_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct tegra_kbc *kbc = platform_get_drvdata(pdev);
mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) { if (device_may_wakeup(&pdev->dev)) {
tegra_kbc_setup_wakekeys(kbc, true); disable_irq(kbc->irq);
enable_irq_wake(kbc->irq); del_timer_sync(&kbc->timer);
tegra_kbc_set_fifo_interrupt(kbc, false);
/* Forcefully clear the interrupt status */ /* Forcefully clear the interrupt status */
writel(0x7, kbc->mmio + KBC_INT_0); writel(0x7, kbc->mmio + KBC_INT_0);
/*
* Store the previous resident time of continuous polling mode.
* Force the keyboard into interrupt mode.
*/
kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0);
writel(0, kbc->mmio + KBC_TO_CNT_0);
tegra_kbc_setup_wakekeys(kbc, true);
msleep(30); msleep(30);
enable_irq_wake(kbc->irq);
} else { } else {
mutex_lock(&kbc->idev->mutex);
if (kbc->idev->users) if (kbc->idev->users)
tegra_kbc_stop(kbc); tegra_kbc_stop(kbc);
mutex_unlock(&kbc->idev->mutex);
} }
mutex_unlock(&kbc->idev->mutex);
return 0; return 0;
} }
...@@ -756,15 +777,22 @@ static int tegra_kbc_resume(struct device *dev) ...@@ -756,15 +777,22 @@ static int tegra_kbc_resume(struct device *dev)
struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct tegra_kbc *kbc = platform_get_drvdata(pdev);
int err = 0; int err = 0;
mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) { if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(kbc->irq); disable_irq_wake(kbc->irq);
tegra_kbc_setup_wakekeys(kbc, false); tegra_kbc_setup_wakekeys(kbc, false);
/* Restore the resident time of continuous polling mode. */
writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
tegra_kbc_set_fifo_interrupt(kbc, true);
enable_irq(kbc->irq);
} else { } else {
mutex_lock(&kbc->idev->mutex);
if (kbc->idev->users) if (kbc->idev->users)
err = tegra_kbc_start(kbc); err = tegra_kbc_start(kbc);
mutex_unlock(&kbc->idev->mutex);
} }
mutex_unlock(&kbc->idev->mutex);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment