diff options
| -rw-r--r-- | Documentation/devicetree/bindings/input/gpio-keys.txt | 8 | ||||
| -rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 145 | ||||
| -rw-r--r-- | include/dt-bindings/input/gpio-keys.h | 13 | ||||
| -rw-r--r-- | include/linux/gpio_keys.h | 2 |
4 files changed, 154 insertions, 14 deletions
diff --git a/Documentation/devicetree/bindings/input/gpio-keys.txt b/Documentation/devicetree/bindings/input/gpio-keys.txt index a94940481e55..996ce84352cb 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys.txt | |||
| @@ -26,6 +26,14 @@ Optional subnode-properties: | |||
| 26 | If not specified defaults to 5. | 26 | If not specified defaults to 5. |
| 27 | - wakeup-source: Boolean, button can wake-up the system. | 27 | - wakeup-source: Boolean, button can wake-up the system. |
| 28 | (Legacy property supported: "gpio-key,wakeup") | 28 | (Legacy property supported: "gpio-key,wakeup") |
| 29 | - wakeup-event-action: Specifies whether the key should wake the | ||
| 30 | system when asserted, when deasserted, or both. This property is | ||
| 31 | only valid for keys that wake up the system (e.g., when the | ||
| 32 | "wakeup-source" property is also provided). | ||
| 33 | Supported values are defined in linux-event-codes.h: | ||
| 34 | EV_ACT_ASSERTED - asserted | ||
| 35 | EV_ACT_DEASSERTED - deasserted | ||
| 36 | EV_ACT_ANY - both asserted and deasserted | ||
| 29 | - linux,can-disable: Boolean, indicates that button is connected | 37 | - linux,can-disable: Boolean, indicates that button is connected |
| 30 | to dedicated (not shared) interrupt which can be disabled to | 38 | to dedicated (not shared) interrupt which can be disabled to |
| 31 | suppress events from the button. | 39 | suppress events from the button. |
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 87e613dc33b8..052e37675086 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/of.h> | 30 | #include <linux/of.h> |
| 31 | #include <linux/of_irq.h> | 31 | #include <linux/of_irq.h> |
| 32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
| 33 | #include <dt-bindings/input/gpio-keys.h> | ||
| 33 | 34 | ||
| 34 | struct gpio_button_data { | 35 | struct gpio_button_data { |
| 35 | const struct gpio_keys_button *button; | 36 | const struct gpio_keys_button *button; |
| @@ -45,6 +46,7 @@ struct gpio_button_data { | |||
| 45 | unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ | 46 | unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ |
| 46 | 47 | ||
| 47 | unsigned int irq; | 48 | unsigned int irq; |
| 49 | unsigned int wakeup_trigger_type; | ||
| 48 | spinlock_t lock; | 50 | spinlock_t lock; |
| 49 | bool disabled; | 51 | bool disabled; |
| 50 | bool key_pressed; | 52 | bool key_pressed; |
| @@ -540,6 +542,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, | |||
| 540 | } | 542 | } |
| 541 | 543 | ||
| 542 | if (bdata->gpiod) { | 544 | if (bdata->gpiod) { |
| 545 | bool active_low = gpiod_is_active_low(bdata->gpiod); | ||
| 546 | |||
| 543 | if (button->debounce_interval) { | 547 | if (button->debounce_interval) { |
| 544 | error = gpiod_set_debounce(bdata->gpiod, | 548 | error = gpiod_set_debounce(bdata->gpiod, |
| 545 | button->debounce_interval * 1000); | 549 | button->debounce_interval * 1000); |
| @@ -568,6 +572,24 @@ static int gpio_keys_setup_key(struct platform_device *pdev, | |||
| 568 | isr = gpio_keys_gpio_isr; | 572 | isr = gpio_keys_gpio_isr; |
| 569 | irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | 573 | irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; |
| 570 | 574 | ||
| 575 | switch (button->wakeup_event_action) { | ||
| 576 | case EV_ACT_ASSERTED: | ||
| 577 | bdata->wakeup_trigger_type = active_low ? | ||
| 578 | IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; | ||
| 579 | break; | ||
| 580 | case EV_ACT_DEASSERTED: | ||
| 581 | bdata->wakeup_trigger_type = active_low ? | ||
| 582 | IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING; | ||
| 583 | break; | ||
| 584 | case EV_ACT_ANY: | ||
| 585 | /* fall through */ | ||
| 586 | default: | ||
| 587 | /* | ||
| 588 | * For other cases, we are OK letting suspend/resume | ||
| 589 | * not reconfigure the trigger type. | ||
| 590 | */ | ||
| 591 | break; | ||
| 592 | } | ||
| 571 | } else { | 593 | } else { |
| 572 | if (!button->irq) { | 594 | if (!button->irq) { |
| 573 | dev_err(dev, "Found button without gpio or irq\n"); | 595 | dev_err(dev, "Found button without gpio or irq\n"); |
| @@ -586,6 +608,11 @@ static int gpio_keys_setup_key(struct platform_device *pdev, | |||
| 586 | 608 | ||
| 587 | isr = gpio_keys_irq_isr; | 609 | isr = gpio_keys_irq_isr; |
| 588 | irqflags = 0; | 610 | irqflags = 0; |
| 611 | |||
| 612 | /* | ||
| 613 | * For IRQ buttons, there is no interrupt for release. | ||
| 614 | * So we don't need to reconfigure the trigger type for wakeup. | ||
| 615 | */ | ||
| 589 | } | 616 | } |
| 590 | 617 | ||
| 591 | bdata->code = &ddata->keymap[idx]; | 618 | bdata->code = &ddata->keymap[idx]; |
| @@ -718,6 +745,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) | |||
| 718 | /* legacy name */ | 745 | /* legacy name */ |
| 719 | fwnode_property_read_bool(child, "gpio-key,wakeup"); | 746 | fwnode_property_read_bool(child, "gpio-key,wakeup"); |
| 720 | 747 | ||
| 748 | fwnode_property_read_u32(child, "wakeup-event-action", | ||
| 749 | &button->wakeup_event_action); | ||
| 750 | |||
| 721 | button->can_disable = | 751 | button->can_disable = |
| 722 | fwnode_property_read_bool(child, "linux,can-disable"); | 752 | fwnode_property_read_bool(child, "linux,can-disable"); |
| 723 | 753 | ||
| @@ -845,19 +875,112 @@ static int gpio_keys_probe(struct platform_device *pdev) | |||
| 845 | return 0; | 875 | return 0; |
| 846 | } | 876 | } |
| 847 | 877 | ||
| 878 | static int __maybe_unused | ||
| 879 | gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata) | ||
| 880 | { | ||
| 881 | int error; | ||
| 882 | |||
| 883 | error = enable_irq_wake(bdata->irq); | ||
| 884 | if (error) { | ||
| 885 | dev_err(bdata->input->dev.parent, | ||
| 886 | "failed to configure IRQ %d as wakeup source: %d\n", | ||
| 887 | bdata->irq, error); | ||
| 888 | return error; | ||
| 889 | } | ||
| 890 | |||
| 891 | if (bdata->wakeup_trigger_type) { | ||
| 892 | error = irq_set_irq_type(bdata->irq, | ||
| 893 | bdata->wakeup_trigger_type); | ||
| 894 | if (error) { | ||
| 895 | dev_err(bdata->input->dev.parent, | ||
| 896 | "failed to set wakeup trigger %08x for IRQ %d: %d\n", | ||
| 897 | bdata->wakeup_trigger_type, bdata->irq, error); | ||
| 898 | disable_irq_wake(bdata->irq); | ||
| 899 | return error; | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | return 0; | ||
| 904 | } | ||
| 905 | |||
| 906 | static void __maybe_unused | ||
| 907 | gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata) | ||
| 908 | { | ||
| 909 | int error; | ||
| 910 | |||
| 911 | /* | ||
| 912 | * The trigger type is always both edges for gpio-based keys and we do | ||
| 913 | * not support changing wakeup trigger for interrupt-based keys. | ||
| 914 | */ | ||
| 915 | if (bdata->wakeup_trigger_type) { | ||
| 916 | error = irq_set_irq_type(bdata->irq, IRQ_TYPE_EDGE_BOTH); | ||
| 917 | if (error) | ||
| 918 | dev_warn(bdata->input->dev.parent, | ||
| 919 | "failed to restore interrupt trigger for IRQ %d: %d\n", | ||
| 920 | bdata->irq, error); | ||
| 921 | } | ||
| 922 | |||
| 923 | error = disable_irq_wake(bdata->irq); | ||
| 924 | if (error) | ||
| 925 | dev_warn(bdata->input->dev.parent, | ||
| 926 | "failed to disable IRQ %d as wake source: %d\n", | ||
| 927 | bdata->irq, error); | ||
| 928 | } | ||
| 929 | |||
| 930 | static int __maybe_unused | ||
| 931 | gpio_keys_enable_wakeup(struct gpio_keys_drvdata *ddata) | ||
| 932 | { | ||
| 933 | struct gpio_button_data *bdata; | ||
| 934 | int error; | ||
| 935 | int i; | ||
| 936 | |||
| 937 | for (i = 0; i < ddata->pdata->nbuttons; i++) { | ||
| 938 | bdata = &ddata->data[i]; | ||
| 939 | if (bdata->button->wakeup) { | ||
| 940 | error = gpio_keys_button_enable_wakeup(bdata); | ||
| 941 | if (error) | ||
| 942 | goto err_out; | ||
| 943 | } | ||
| 944 | bdata->suspended = true; | ||
| 945 | } | ||
| 946 | |||
| 947 | return 0; | ||
| 948 | |||
| 949 | err_out: | ||
| 950 | while (i--) { | ||
| 951 | bdata = &ddata->data[i]; | ||
| 952 | if (bdata->button->wakeup) | ||
| 953 | gpio_keys_button_disable_wakeup(bdata); | ||
| 954 | bdata->suspended = false; | ||
| 955 | } | ||
| 956 | |||
| 957 | return error; | ||
| 958 | } | ||
| 959 | |||
| 960 | static void __maybe_unused | ||
| 961 | gpio_keys_disable_wakeup(struct gpio_keys_drvdata *ddata) | ||
| 962 | { | ||
| 963 | struct gpio_button_data *bdata; | ||
| 964 | int i; | ||
| 965 | |||
| 966 | for (i = 0; i < ddata->pdata->nbuttons; i++) { | ||
| 967 | bdata = &ddata->data[i]; | ||
| 968 | bdata->suspended = false; | ||
| 969 | if (irqd_is_wakeup_set(irq_get_irq_data(bdata->irq))) | ||
| 970 | gpio_keys_button_disable_wakeup(bdata); | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 848 | static int __maybe_unused gpio_keys_suspend(struct device *dev) | 974 | static int __maybe_unused gpio_keys_suspend(struct device *dev) |
| 849 | { | 975 | { |
| 850 | struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); | 976 | struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); |
| 851 | struct input_dev *input = ddata->input; | 977 | struct input_dev *input = ddata->input; |
| 852 | int i; | 978 | int error; |
| 853 | 979 | ||
| 854 | if (device_may_wakeup(dev)) { | 980 | if (device_may_wakeup(dev)) { |
| 855 | for (i = 0; i < ddata->pdata->nbuttons; i++) { | 981 | error = gpio_keys_enable_wakeup(ddata); |
| 856 | struct gpio_button_data *bdata = &ddata->data[i]; | 982 | if (error) |
| 857 | if (bdata->button->wakeup) | 983 | return error; |
| 858 | enable_irq_wake(bdata->irq); | ||
| 859 | bdata->suspended = true; | ||
| 860 | } | ||
| 861 | } else { | 984 | } else { |
| 862 | mutex_lock(&input->mutex); | 985 | mutex_lock(&input->mutex); |
| 863 | if (input->users) | 986 | if (input->users) |
| @@ -873,15 +996,9 @@ static int __maybe_unused gpio_keys_resume(struct device *dev) | |||
| 873 | struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); | 996 | struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); |
| 874 | struct input_dev *input = ddata->input; | 997 | struct input_dev *input = ddata->input; |
| 875 | int error = 0; | 998 | int error = 0; |
| 876 | int i; | ||
| 877 | 999 | ||
| 878 | if (device_may_wakeup(dev)) { | 1000 | if (device_may_wakeup(dev)) { |
| 879 | for (i = 0; i < ddata->pdata->nbuttons; i++) { | 1001 | gpio_keys_disable_wakeup(ddata); |
| 880 | struct gpio_button_data *bdata = &ddata->data[i]; | ||
| 881 | if (bdata->button->wakeup) | ||
| 882 | disable_irq_wake(bdata->irq); | ||
| 883 | bdata->suspended = false; | ||
| 884 | } | ||
| 885 | } else { | 1002 | } else { |
| 886 | mutex_lock(&input->mutex); | 1003 | mutex_lock(&input->mutex); |
| 887 | if (input->users) | 1004 | if (input->users) |
diff --git a/include/dt-bindings/input/gpio-keys.h b/include/dt-bindings/input/gpio-keys.h new file mode 100644 index 000000000000..8962df79e753 --- /dev/null +++ b/include/dt-bindings/input/gpio-keys.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * This header provides constants for gpio keys bindings. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _DT_BINDINGS_GPIO_KEYS_H | ||
| 7 | #define _DT_BINDINGS_GPIO_KEYS_H | ||
| 8 | |||
| 9 | #define EV_ACT_ANY 0x00 /* asserted or deasserted */ | ||
| 10 | #define EV_ACT_ASSERTED 0x01 /* asserted */ | ||
| 11 | #define EV_ACT_DEASSERTED 0x02 /* deasserted */ | ||
| 12 | |||
| 13 | #endif /* _DT_BINDINGS_GPIO_KEYS_H */ | ||
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index d06bf77400f1..7160df54a6fe 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h | |||
| @@ -13,6 +13,7 @@ struct device; | |||
| 13 | * @desc: label that will be attached to button's gpio | 13 | * @desc: label that will be attached to button's gpio |
| 14 | * @type: input event type (%EV_KEY, %EV_SW, %EV_ABS) | 14 | * @type: input event type (%EV_KEY, %EV_SW, %EV_ABS) |
| 15 | * @wakeup: configure the button as a wake-up source | 15 | * @wakeup: configure the button as a wake-up source |
| 16 | * @wakeup_event_action: event action to trigger wakeup | ||
| 16 | * @debounce_interval: debounce ticks interval in msecs | 17 | * @debounce_interval: debounce ticks interval in msecs |
| 17 | * @can_disable: %true indicates that userspace is allowed to | 18 | * @can_disable: %true indicates that userspace is allowed to |
| 18 | * disable button via sysfs | 19 | * disable button via sysfs |
| @@ -26,6 +27,7 @@ struct gpio_keys_button { | |||
| 26 | const char *desc; | 27 | const char *desc; |
| 27 | unsigned int type; | 28 | unsigned int type; |
| 28 | int wakeup; | 29 | int wakeup; |
| 30 | int wakeup_event_action; | ||
| 29 | int debounce_interval; | 31 | int debounce_interval; |
| 30 | bool can_disable; | 32 | bool can_disable; |
| 31 | int value; | 33 | int value; |
