From patchwork Sun May 13 12:44:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 8574 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 11A0D23EAB for ; Sun, 13 May 2012 12:44:18 +0000 (UTC) Received: from mail-ob0-f180.google.com (mail-ob0-f180.google.com [209.85.214.180]) by fiordland.canonical.com (Postfix) with ESMTP id B03B6A187E6 for ; Sun, 13 May 2012 12:44:17 +0000 (UTC) Received: by mail-ob0-f180.google.com with SMTP id un3so3901196obb.11 for ; Sun, 13 May 2012 05:44:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:mime-version:content-type :x-gm-message-state; bh=pACbZCb/HN7ofmt9krhw6MgibFXdcdlvbYqNHhV6v60=; b=EgRdeZxZohAwV5SuaPrVXWFtehagqjTPykgs1lV0Ei1jiIK53gVbrRKS8mtD4O3oPX aQiT/nWODSyQlaSYp/PDmzi+J8HQvRuCMvFFFZjltWNBErffV9BdjKdjKq7wC24joTic y5Cd8BGLzva6QuFXb7qmMXl5KQs+YVe7YCrvA2YpwlAWwru/AQv+lP25eEqj9yK5qFWJ 9Jc03T0f8zga7NE+wkzEQOdP68/SbsXPWVV+6+YzL7lDof4ZngHgiFdjHlV5rJsNhOAP n9rDOKVsAOwDmBV9eifM3NM/1q3QpQL9SSCXPQ/ZQX9rkXNAuahloJaz8LkJOWBqzSRu DpQA== Received: by 10.50.89.168 with SMTP id bp8mr2367254igb.3.1336913057403; Sun, 13 May 2012 05:44:17 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.73.147 with SMTP id q19csp286736ibj; Sun, 13 May 2012 05:44:16 -0700 (PDT) Received: by 10.14.97.77 with SMTP id s53mr762289eef.104.1336913056060; Sun, 13 May 2012 05:44:16 -0700 (PDT) Received: from eu1sys200aog102.obsmtp.com (eu1sys200aog102.obsmtp.com. [207.126.144.113]) by mx.google.com with SMTP id z15si214930eef.142.2012.05.13.05.44.14 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 13 May 2012 05:44:16 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.113 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.113; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.113 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob102.postini.com ([207.126.147.11]) with SMTP ID DSNKT6+snaSo5FEQMRHsEKJuxrp8AXe05znV@postini.com; Sun, 13 May 2012 12:44:15 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 4033776; Sun, 13 May 2012 12:44:13 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id C3F142072; Sun, 13 May 2012 12:44:12 +0000 (GMT) Received: from exdcvycastm003.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm003", Issuer "exdcvycastm003" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id CC7C624C080; Sun, 13 May 2012 14:44:05 +0200 (CEST) Received: from steludxu4075.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.1) with Microsoft SMTP Server (TLS) id 8.3.83.0; Sun, 13 May 2012 14:44:12 +0200 From: Linus Walleij To: Dmitry Torokhov Cc: , Karl-Johan Perntz , Linus Walleij Subject: [PATCH 5/7] input/nomadik-ske: move key scanning to delayed work Date: Sun, 13 May 2012 14:44:09 +0200 Message-ID: <1336913049-10153-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.9.2 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmAshDeOZL9GI3UpbMI2qSxe37emqalG0XiIBQT22liBkw7PNd/s3yzZd2YtGW0I5cDZng/ From: Karl-Johan Perntz Move the key scanning to a delayed work thread, drop the threaded IRQ since all the IRQ work can now be done quickly. Signed-off-by: Karl-Johan Perntz Tested-by: Naga Radesh Y Signed-off-by: Linus Walleij --- arch/arm/plat-nomadik/include/plat/ske.h | 3 + drivers/input/keyboard/nomadik-ske-keypad.c | 134 ++++++++++++++++++++++----- 2 files changed, 115 insertions(+), 22 deletions(-) diff --git a/arch/arm/plat-nomadik/include/plat/ske.h b/arch/arm/plat-nomadik/include/plat/ske.h index 31382fb..d6002dd 100644 --- a/arch/arm/plat-nomadik/include/plat/ske.h +++ b/arch/arm/plat-nomadik/include/plat/ske.h @@ -22,6 +22,9 @@ #define SKE_MIS 0x18 #define SKE_ICR 0x1C +#define SKE_KPD_MAX_ROWS 8 +#define SKE_KPD_MAX_COLS 8 + /* * Keypad module */ diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index c69a149..86f7d41 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,10 @@ #define SKE_NUM_ASRX_REGISTERS (4) #define KEY_PRESSED_DELAY 10 + +#define KEY_REPORTED 1 +#define KEY_PRESSED 2 + /** * struct ske_keypad - data structure used by keypad driver * @dev: Pointer to the structure device @@ -60,6 +65,9 @@ * @keymap: matrix scan code table for keycodes * @clk: clock structure pointer * @ske_keypad_lock: lock used while writting into registers + * @key_pressed: hold the key state + * @keys: matrix holding key status + * @scan_work: delayed work for scaning new key actions */ struct ske_keypad { struct device *dev; @@ -70,6 +78,9 @@ struct ske_keypad { unsigned short keymap[SKE_KPD_KEYMAP_SIZE]; struct clk *clk; spinlock_t ske_keypad_lock; + int key_pressed; + u8 keys[SKE_KPD_MAX_ROWS][SKE_KPD_MAX_COLS]; + struct delayed_work scan_work; }; static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr, @@ -141,9 +152,7 @@ static int __init ske_keypad_chip_init(struct ske_keypad *keypad) static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col) { int row = 0, code, pos; - struct input_dev *input = keypad->input; u32 ske_ris; - int key_pressed; int num_of_rows; /* find out the row */ @@ -155,11 +164,15 @@ static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col) code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT); ske_ris = readl(keypad->reg_base + SKE_RIS); - key_pressed = ske_ris & SKE_KPRISA; + keypad->key_pressed = ske_ris & SKE_KPRISA; + + dev_dbg(keypad->dev, + "%s key_pressed:%d code:%d row:%d col:%d\n", + __func__, keypad->key_pressed, code, row, col); + + if (keypad->key_pressed) + keypad->keys[row][col] |= KEY_PRESSED; - input_event(input, EV_MSC, MSC_SCAN, code); - input_report_key(input, keypad->keymap[code], key_pressed); - input_sync(input); num_of_rows--; } while (num_of_rows); } @@ -196,27 +209,101 @@ static void ske_keypad_read_data(struct ske_keypad *keypad) } } -static irqreturn_t ske_keypad_irq(int irq, void *dev_id) +static void ske_keypad_scan_work(struct work_struct *work) { - struct ske_keypad *keypad = dev_id; - int timeout = keypad->board->debounce_ms; - - /* disable auto scan interrupt; mask the interrupt generated */ - ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0); - ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA); + int timeout = 10; + int i, j, code; + struct ske_keypad *keypad = container_of(work, + struct ske_keypad, scan_work.work); + struct input_dev *input = keypad->input; - while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --timeout) + /* Wait for autoscan to complete */ + while (readl(keypad->reg_base + SKE_CR) & SKE_KPASON) cpu_relax(); /* SKEx registers are stable and can be read */ ske_keypad_read_data(keypad); - /* wait until raw interrupt is clear */ - while ((readl(keypad->reg_base + SKE_RIS)) && --timeout) - msleep(KEY_PRESSED_DELAY); + /* Check for key actions */ + for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { + for (j = 0; j < SKE_KPD_MAX_COLS; j++) { + switch (keypad->keys[i][j]) { + case KEY_REPORTED: + /** + * Key was reported but is no longer pressed, + * report it as released. + */ + code = MATRIX_SCAN_CODE(i, j, + SKE_KEYPAD_ROW_SHIFT); + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, keypad->keymap[code], + 0); + input_sync(input); + keypad->keys[i][j] = 0; + dev_dbg(keypad->dev, + "%s Key release reported, code:%d\n", + __func__, code); + break; + case KEY_PRESSED: + /* Key pressed but not yet reported, report */ + code = MATRIX_SCAN_CODE(i, j, + SKE_KEYPAD_ROW_SHIFT); + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, keypad->keymap[code], + 1); + input_sync(input); + dev_dbg(keypad->dev, + "%s Key press reported, code:%d\n", + __func__, code); + /* Intentional fall though */ + case (KEY_REPORTED | KEY_PRESSED): + /** + * Key pressed and reported, just reset + * KEY_PRESSED for next scan + */ + keypad->keys[i][j] = KEY_REPORTED; + break; + } + } + } + + if (keypad->key_pressed) { + /* + * Key still pressed, schedule work to poll changes in 100 ms + * After increasing the delay from 50 to 100 it is taking + * 2% to 3% load on average. + */ + schedule_delayed_work(&keypad->scan_work, + msecs_to_jiffies(100)); + } else { + /* For safety measures, clear interrupt once more */ + ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA); + + /* Wait for raw interrupt to clear */ + while ((readl(keypad->reg_base + SKE_RIS) & SKE_KPRISA) && + --timeout) { + udelay(10); + } + + if (!timeout) + dev_err(keypad->dev, + "%s Timeed out waiting on irq to clear\n", + __func__); - /* enable auto scan interrupts */ - ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA); + /* Enable auto scan interrupts */ + ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA); + } +} + +static irqreturn_t ske_keypad_irq(int irq, void *dev_id) +{ + struct ske_keypad *keypad = dev_id; + + /* disable auto scan interrupt; mask the interrupt generated */ + ske_keypad_set_bits(keypad, SKE_IMSC, SKE_KPIMA, 0x0); + ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA); + + schedule_delayed_work(&keypad->scan_work, 0); return IRQ_HANDLED; } @@ -314,6 +401,7 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->input = input; keypad->reg_base = reg_base; keypad->clk = clk; + INIT_DELAYED_WORK(&keypad->scan_work, ske_keypad_scan_work); /* allocations are sane, we begin HW initialization */ clk_enable(keypad->clk); @@ -324,8 +412,8 @@ static int __init ske_keypad_probe(struct platform_device *pdev) goto out_unregisterinput; } - ret = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq, - IRQF_ONESHOT, "ske-keypad", keypad); + ret = request_irq(keypad->irq, ske_keypad_irq, 0, + "ske-keypad", keypad); if (ret) { dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq); goto out_unregisterinput; @@ -360,8 +448,9 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev) struct ske_keypad *keypad = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - input_unregister_device(keypad->input); + cancel_delayed_work_sync(&keypad->scan_work); + input_unregister_device(keypad->input); clk_disable(keypad->clk); clk_put(keypad->clk); @@ -385,6 +474,7 @@ static int ske_keypad_suspend(struct device *dev) if (device_may_wakeup(dev)) enable_irq_wake(irq); else { + cancel_delayed_work_sync(&keypad->scan_work); disable_irq(irq); ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0); clk_disable(keypad->clk);