summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/tegra-kbc.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index e560e428db98..134960a219ea 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -55,6 +55,7 @@
#define KBC_ROW_CFG0_0 0x8
#define KBC_COL_CFG0_0 0x18
+#define KBC_TO_CNT_0 0x24
#define KBC_INIT_DLY_0 0x28
#define KBC_RPT_DLY_0 0x2c
#define KBC_KP_ENT0_0 0x30
@@ -62,6 +63,8 @@
#define KBC_ROW0_MASK_0 0x38
#define KBC_ROW_SHIFT 3
+#define DEFAULT_SCAN_COUNT 2
+#define DEFAULT_INIT_DLY 5
struct tegra_kbc {
void __iomem *mmio;
@@ -80,6 +83,8 @@ struct tegra_kbc {
unsigned int num_pressed_keys;
struct timer_list timer;
struct clk *clk;
+ unsigned long scan_timeout_count;
+ unsigned long one_scan_time;
};
static const u32 tegra_kbc_default_keymap[] = {
@@ -495,6 +500,9 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
val |= KBC_CONTROL_KBC_EN; /* enable */
writel(val, kbc->mmio + KBC_CONTROL_0);
+ writel(DEFAULT_INIT_DLY, kbc->mmio + KBC_INIT_DLY_0);
+ writel(kbc->scan_timeout_count, kbc->mmio + KBC_TO_CNT_0);
+
/*
* Compute the delay(ns) from interrupt mode to continuous polling
* mode so the timer routine is scheduled appropriately.
@@ -602,6 +610,9 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
+ unsigned long scan_tc;
+
+ dev_dbg(&pdev->dev, "KBC: tegra_kbc_probe\n");
if (!pdata)
return -EINVAL;
@@ -673,6 +684,17 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
+ if (pdata->scan_count)
+ scan_tc = DEFAULT_INIT_DLY + (scan_time_rows +
+ pdata->repeat_cnt) * pdata->scan_count;
+ else
+ scan_tc = DEFAULT_INIT_DLY + (scan_time_rows +
+ pdata->repeat_cnt) * DEFAULT_SCAN_COUNT;
+
+ kbc->one_scan_time = scan_time_rows + pdata->repeat_cnt;
+ /* Bit 19:0 is for scan timeout count */
+ kbc->scan_timeout_count = scan_tc & 0xFFFFF;
+
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
@@ -756,8 +778,27 @@ static int tegra_kbc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+ int timeout;
+ unsigned long int_st;
+ dev_dbg(&pdev->dev, "KBC: tegra_kbc_suspend\n");
if (device_may_wakeup(&pdev->dev)) {
+ timeout = DIV_ROUND_UP((kbc->scan_timeout_count +
+ kbc->one_scan_time), 32);
+ timeout = DIV_ROUND_UP(timeout, 10);
+ while (timeout--) {
+ int_st = readl(kbc->mmio + KBC_INT_0);
+ if (int_st & 0x8) {
+ msleep(10);
+ continue;
+ }
+ break;
+ }
+ int_st = readl(kbc->mmio + KBC_INT_0);
+ if (int_st & 0x8)
+ dev_err(&pdev->dev, "KBC: Controller is not in "
+ "wakeupmode\n");
+
tegra_kbc_setup_wakekeys(kbc, true);
enable_irq_wake(kbc->irq);
/* Forcefully clear the interrupt status */