aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/gpio-keys.txt8
-rw-r--r--drivers/input/keyboard/gpio_keys.c145
-rw-r--r--include/dt-bindings/input/gpio-keys.h13
-rw-r--r--include/linux/gpio_keys.h2
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
34struct gpio_button_data { 35struct 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
878static int __maybe_unused
879gpio_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
906static void __maybe_unused
907gpio_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
930static int __maybe_unused
931gpio_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
949err_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
960static void __maybe_unused
961gpio_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
848static int __maybe_unused gpio_keys_suspend(struct device *dev) 974static 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;