diff options
Diffstat (limited to 'drivers/input/keyboard/tegra-kbc.c')
-rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 41 |
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 */ |