]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Input: nspire-keypad - enable interrupts only when opened
authorFabian Vogt <fabian@ritter-vogt.de>
Tue, 23 Mar 2021 17:45:55 +0000 (10:45 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 23 Mar 2021 17:55:10 +0000 (10:55 -0700)
The driver registers an interrupt handler in _probe, but didn't configure
them until later when the _open function is called. In between, the keypad
can fire an IRQ due to touchpad activity, which the handler ignores. This
causes the kernel to disable the interrupt, blocking the keypad from
working.

Fix this by disabling interrupts before registering the handler.
Additionally, disable them in _close, so that they're only enabled while
open.

Fixes: fc4f31461892 ("Input: add TI-Nspire keypad support")
Signed-off-by: Fabian Vogt <fabian@ritter-vogt.de>
Link: https://lore.kernel.org/r/3383725.iizBOSrK1V@linux-e202.suse.de
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/keyboard/nspire-keypad.c

index 63d5e488137dc037d7fc1bab44a66c2a8480308c..e9fa1423f136090ebeabafb4e74810c56a558f92 100644 (file)
@@ -93,9 +93,15 @@ static irqreturn_t nspire_keypad_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
+static int nspire_keypad_open(struct input_dev *input)
 {
+       struct nspire_keypad *keypad = input_get_drvdata(input);
        unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
+       int error;
+
+       error = clk_prepare_enable(keypad->clk);
+       if (error)
+               return error;
 
        cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
        if (cycles_per_us == 0)
@@ -121,30 +127,6 @@ static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
        keypad->int_mask = 1 << 1;
        writel(keypad->int_mask, keypad->reg_base + KEYPAD_INTMSK);
 
-       /* Disable GPIO interrupts to prevent hanging on touchpad */
-       /* Possibly used to detect touchpad events */
-       writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
-       /* Acknowledge existing interrupts */
-       writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
-
-       return 0;
-}
-
-static int nspire_keypad_open(struct input_dev *input)
-{
-       struct nspire_keypad *keypad = input_get_drvdata(input);
-       int error;
-
-       error = clk_prepare_enable(keypad->clk);
-       if (error)
-               return error;
-
-       error = nspire_keypad_chip_init(keypad);
-       if (error) {
-               clk_disable_unprepare(keypad->clk);
-               return error;
-       }
-
        return 0;
 }
 
@@ -152,6 +134,11 @@ static void nspire_keypad_close(struct input_dev *input)
 {
        struct nspire_keypad *keypad = input_get_drvdata(input);
 
+       /* Disable interrupts */
+       writel(0, keypad->reg_base + KEYPAD_INTMSK);
+       /* Acknowledge existing interrupts */
+       writel(~0, keypad->reg_base + KEYPAD_INT);
+
        clk_disable_unprepare(keypad->clk);
 }
 
@@ -210,6 +197,25 @@ static int nspire_keypad_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       error = clk_prepare_enable(keypad->clk);
+       if (error) {
+               dev_err(&pdev->dev, "failed to enable clock\n");
+               return error;
+       }
+
+       /* Disable interrupts */
+       writel(0, keypad->reg_base + KEYPAD_INTMSK);
+       /* Acknowledge existing interrupts */
+       writel(~0, keypad->reg_base + KEYPAD_INT);
+
+       /* Disable GPIO interrupts to prevent hanging on touchpad */
+       /* Possibly used to detect touchpad events */
+       writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
+       /* Acknowledge existing GPIO interrupts */
+       writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
+
+       clk_disable_unprepare(keypad->clk);
+
        input_set_drvdata(input, keypad);
 
        input->id.bustype = BUS_HOST;