Commit a33466e31213cd7c46696160d3db78680b58f6a3
Committed by
Dmitry Torokhov
1 parent
885c316d77
Exists in
master
and in
39 other branches
Input: gpio-keys debouncing support
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 2 changed files with 70 additions and 20 deletions Side-by-side Diff
drivers/input/keyboard/gpio_keys.c
... | ... | @@ -26,23 +26,54 @@ |
26 | 26 | |
27 | 27 | #include <asm/gpio.h> |
28 | 28 | |
29 | +struct gpio_button_data { | |
30 | + struct gpio_keys_button *button; | |
31 | + struct input_dev *input; | |
32 | + struct timer_list timer; | |
33 | +}; | |
34 | + | |
35 | +struct gpio_keys_drvdata { | |
36 | + struct input_dev *input; | |
37 | + struct gpio_button_data data[0]; | |
38 | +}; | |
39 | + | |
40 | +static void gpio_keys_report_event(struct gpio_keys_button *button, | |
41 | + struct input_dev *input) | |
42 | +{ | |
43 | + unsigned int type = button->type ?: EV_KEY; | |
44 | + int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; | |
45 | + | |
46 | + input_event(input, type, button->code, !!state); | |
47 | + input_sync(input); | |
48 | +} | |
49 | + | |
50 | +static void gpio_check_button(unsigned long _data) | |
51 | +{ | |
52 | + struct gpio_button_data *data = (struct gpio_button_data *)_data; | |
53 | + | |
54 | + gpio_keys_report_event(data->button, data->input); | |
55 | +} | |
56 | + | |
29 | 57 | static irqreturn_t gpio_keys_isr(int irq, void *dev_id) |
30 | 58 | { |
31 | - int i; | |
32 | 59 | struct platform_device *pdev = dev_id; |
33 | 60 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
34 | - struct input_dev *input = platform_get_drvdata(pdev); | |
61 | + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); | |
62 | + int i; | |
35 | 63 | |
36 | 64 | for (i = 0; i < pdata->nbuttons; i++) { |
37 | 65 | struct gpio_keys_button *button = &pdata->buttons[i]; |
38 | - int gpio = button->gpio; | |
39 | 66 | |
40 | - if (irq == gpio_to_irq(gpio)) { | |
41 | - unsigned int type = button->type ?: EV_KEY; | |
42 | - int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; | |
67 | + if (irq == gpio_to_irq(button->gpio)) { | |
68 | + struct gpio_button_data *bdata = &ddata->data[i]; | |
43 | 69 | |
44 | - input_event(input, type, button->code, !!state); | |
45 | - input_sync(input); | |
70 | + if (button->debounce_interval) | |
71 | + mod_timer(&bdata->timer, | |
72 | + jiffies + | |
73 | + msecs_to_jiffies(button->debounce_interval)); | |
74 | + else | |
75 | + gpio_keys_report_event(button, bdata->input); | |
76 | + | |
46 | 77 | return IRQ_HANDLED; |
47 | 78 | } |
48 | 79 | } |
49 | 80 | |
50 | 81 | |
51 | 82 | |
52 | 83 | |
... | ... | @@ -53,18 +84,22 @@ |
53 | 84 | static int __devinit gpio_keys_probe(struct platform_device *pdev) |
54 | 85 | { |
55 | 86 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
87 | + struct gpio_keys_drvdata *ddata; | |
56 | 88 | struct input_dev *input; |
57 | 89 | int i, error; |
58 | 90 | int wakeup = 0; |
59 | 91 | |
92 | + ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + | |
93 | + pdata->nbuttons * sizeof(struct gpio_button_data), | |
94 | + GFP_KERNEL); | |
60 | 95 | input = input_allocate_device(); |
61 | - if (!input) | |
62 | - return -ENOMEM; | |
96 | + if (!ddata || !input) { | |
97 | + error = -ENOMEM; | |
98 | + goto fail1; | |
99 | + } | |
63 | 100 | |
64 | - platform_set_drvdata(pdev, input); | |
101 | + platform_set_drvdata(pdev, ddata); | |
65 | 102 | |
66 | - input->evbit[0] = BIT_MASK(EV_KEY); | |
67 | - | |
68 | 103 | input->name = pdev->name; |
69 | 104 | input->phys = "gpio-keys/input0"; |
70 | 105 | input->dev.parent = &pdev->dev; |
71 | 106 | |
72 | 107 | |
73 | 108 | |
... | ... | @@ -74,16 +109,23 @@ |
74 | 109 | input->id.product = 0x0001; |
75 | 110 | input->id.version = 0x0100; |
76 | 111 | |
112 | + ddata->input = input; | |
113 | + | |
77 | 114 | for (i = 0; i < pdata->nbuttons; i++) { |
78 | 115 | struct gpio_keys_button *button = &pdata->buttons[i]; |
116 | + struct gpio_button_data *bdata = &ddata->data[i]; | |
79 | 117 | int irq; |
80 | 118 | unsigned int type = button->type ?: EV_KEY; |
81 | 119 | |
120 | + bdata->input = input; | |
121 | + setup_timer(&bdata->timer, | |
122 | + gpio_check_button, (unsigned long)bdata); | |
123 | + | |
82 | 124 | error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); |
83 | 125 | if (error < 0) { |
84 | 126 | pr_err("gpio-keys: failed to request GPIO %d," |
85 | 127 | " error %d\n", button->gpio, error); |
86 | - goto fail; | |
128 | + goto fail2; | |
87 | 129 | } |
88 | 130 | |
89 | 131 | error = gpio_direction_input(button->gpio); |
... | ... | @@ -92,7 +134,7 @@ |
92 | 134 | " direction for GPIO %d, error %d\n", |
93 | 135 | button->gpio, error); |
94 | 136 | gpio_free(button->gpio); |
95 | - goto fail; | |
137 | + goto fail2; | |
96 | 138 | } |
97 | 139 | |
98 | 140 | irq = gpio_to_irq(button->gpio); |
... | ... | @@ -102,7 +144,7 @@ |
102 | 144 | " for GPIO %d, error %d\n", |
103 | 145 | button->gpio, error); |
104 | 146 | gpio_free(button->gpio); |
105 | - goto fail; | |
147 | + goto fail2; | |
106 | 148 | } |
107 | 149 | |
108 | 150 | error = request_irq(irq, gpio_keys_isr, |
... | ... | @@ -114,7 +156,7 @@ |
114 | 156 | pr_err("gpio-keys: Unable to claim irq %d; error %d\n", |
115 | 157 | irq, error); |
116 | 158 | gpio_free(button->gpio); |
117 | - goto fail; | |
159 | + goto fail2; | |
118 | 160 | } |
119 | 161 | |
120 | 162 | if (button->wakeup) |
121 | 163 | |
122 | 164 | |
123 | 165 | |
124 | 166 | |
... | ... | @@ -127,21 +169,25 @@ |
127 | 169 | if (error) { |
128 | 170 | pr_err("gpio-keys: Unable to register input device, " |
129 | 171 | "error: %d\n", error); |
130 | - goto fail; | |
172 | + goto fail2; | |
131 | 173 | } |
132 | 174 | |
133 | 175 | device_init_wakeup(&pdev->dev, wakeup); |
134 | 176 | |
135 | 177 | return 0; |
136 | 178 | |
137 | - fail: | |
179 | + fail2: | |
138 | 180 | while (--i >= 0) { |
139 | 181 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); |
182 | + if (pdata->buttons[i].debounce_interval) | |
183 | + del_timer_sync(&ddata->data[i].timer); | |
140 | 184 | gpio_free(pdata->buttons[i].gpio); |
141 | 185 | } |
142 | 186 | |
143 | 187 | platform_set_drvdata(pdev, NULL); |
188 | + fail1: | |
144 | 189 | input_free_device(input); |
190 | + kfree(ddata); | |
145 | 191 | |
146 | 192 | return error; |
147 | 193 | } |
... | ... | @@ -149,7 +195,8 @@ |
149 | 195 | static int __devexit gpio_keys_remove(struct platform_device *pdev) |
150 | 196 | { |
151 | 197 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
152 | - struct input_dev *input = platform_get_drvdata(pdev); | |
198 | + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); | |
199 | + struct input_dev *input = ddata->input; | |
153 | 200 | int i; |
154 | 201 | |
155 | 202 | device_init_wakeup(&pdev->dev, 0); |
... | ... | @@ -157,6 +204,8 @@ |
157 | 204 | for (i = 0; i < pdata->nbuttons; i++) { |
158 | 205 | int irq = gpio_to_irq(pdata->buttons[i].gpio); |
159 | 206 | free_irq(irq, pdev); |
207 | + if (pdata->buttons[i].debounce_interval) | |
208 | + del_timer_sync(&ddata->data[i].timer); | |
160 | 209 | gpio_free(pdata->buttons[i].gpio); |
161 | 210 | } |
162 | 211 |
include/linux/gpio_keys.h