Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: gpio_keys - allow separating gpio and irq in device tree

This change allows specify interrupt for buttons separately form gpio,
potentially allowing to form several "clusters" of buttons on
different interrupts.

Button defined without both gpio and irq in device tree is a hared error
instead of a warning now.

Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+33 -26
+7 -3
Documentation/devicetree/bindings/input/gpio-keys.txt
··· 10 10 Each button (key) is represented as a sub-node of "gpio-keys": 11 11 Subnode properties: 12 12 13 + - gpios: OF device-tree gpio specification. 14 + - interrupts: the interrupt line for that input. 13 15 - label: Descriptive name of the key. 14 16 - linux,code: Keycode to emit. 15 17 16 - Required mutual exclusive subnode-properties: 17 - - gpios: OF device-tree gpio specification. 18 - - interrupts: the interrupt line for that input 18 + Note that either "interrupts" or "gpios" properties can be omitted, but not 19 + both at the same time. Specifying both properties is allowed. 19 20 20 21 Optional subnode-properties: 21 22 - linux,input-type: Specify event type this button/key generates. ··· 24 23 - debounce-interval: Debouncing interval time in milliseconds. 25 24 If not specified defaults to 5. 26 25 - gpio-key,wakeup: Boolean, button can wake-up the system. 26 + - linux,can-disable: Boolean, indicates that button is connected 27 + to dedicated (not shared) interrupt which can be disabled to 28 + suppress events from the button. 27 29 28 30 Example nodes: 29 31
+26 -23
drivers/input/keyboard/gpio_keys.c
··· 470 470 button->debounce_interval; 471 471 } 472 472 473 - irq = gpio_to_irq(button->gpio); 474 - if (irq < 0) { 475 - error = irq; 476 - dev_err(dev, 477 - "Unable to get irq number for GPIO %d, error %d\n", 478 - button->gpio, error); 479 - return error; 473 + if (button->irq) { 474 + bdata->irq = button->irq; 475 + } else { 476 + irq = gpio_to_irq(button->gpio); 477 + if (irq < 0) { 478 + error = irq; 479 + dev_err(dev, 480 + "Unable to get irq number for GPIO %d, error %d\n", 481 + button->gpio, error); 482 + return error; 483 + } 484 + bdata->irq = irq; 480 485 } 481 - bdata->irq = irq; 482 486 483 487 INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); 484 488 setup_timer(&bdata->timer, ··· 622 618 623 619 i = 0; 624 620 for_each_child_of_node(node, pp) { 625 - int gpio = -1; 626 621 enum of_gpio_flags flags; 627 622 628 623 button = &pdata->buttons[i++]; 629 624 630 - if (!of_find_property(pp, "gpios", NULL)) { 631 - button->irq = irq_of_parse_and_map(pp, 0); 632 - if (button->irq == 0) { 633 - i--; 634 - pdata->nbuttons--; 635 - dev_warn(dev, "Found button without gpios or irqs\n"); 636 - continue; 637 - } 638 - } else { 639 - gpio = of_get_gpio_flags(pp, 0, &flags); 640 - if (gpio < 0) { 641 - error = gpio; 625 + button->gpio = of_get_gpio_flags(pp, 0, &flags); 626 + if (button->gpio < 0) { 627 + error = button->gpio; 628 + if (error != -ENOENT) { 642 629 if (error != -EPROBE_DEFER) 643 630 dev_err(dev, 644 631 "Failed to get gpio flags, error: %d\n", 645 632 error); 646 633 return ERR_PTR(error); 647 634 } 635 + } else { 636 + button->active_low = flags & OF_GPIO_ACTIVE_LOW; 648 637 } 649 638 650 - button->gpio = gpio; 651 - button->active_low = flags & OF_GPIO_ACTIVE_LOW; 639 + button->irq = irq_of_parse_and_map(pp, 0); 640 + 641 + if (!gpio_is_valid(button->gpio) && !button->irq) { 642 + dev_err(dev, "Found button without gpios or irqs\n"); 643 + return ERR_PTR(-EINVAL); 644 + } 652 645 653 646 if (of_property_read_u32(pp, "linux,code", &button->code)) { 654 647 dev_err(dev, "Button without keycode: 0x%x\n", ··· 659 658 button->type = EV_KEY; 660 659 661 660 button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); 661 + 662 + button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); 662 663 663 664 if (of_property_read_u32(pp, "debounce-interval", 664 665 &button->debounce_interval))