]>
Commit | Line | Data |
---|---|---|
420818f9 AH |
1 | /* drivers/input/misc/gpio_input.c |
2 | * | |
3 | * Copyright (C) 2007 Google, Inc. | |
4 | * | |
5 | * This software is licensed under the terms of the GNU General Public | |
6 | * License version 2, as published by the Free Software Foundation, and | |
7 | * may be copied, distributed, and modified under those terms. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/kernel.h> | |
17 | #include <linux/gpio.h> | |
18 | #include <linux/gpio_event.h> | |
19 | #include <linux/hrtimer.h> | |
20 | #include <linux/input.h> | |
21 | #include <linux/interrupt.h> | |
5a0e3ad6 | 22 | #include <linux/slab.h> |
420818f9 AH |
23 | |
24 | enum { | |
25 | DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */ | |
26 | DEBOUNCE_PRESSED = BIT(1), | |
27 | DEBOUNCE_NOTPRESSED = BIT(2), | |
28 | DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */ | |
29 | DEBOUNCE_POLL = BIT(4), /* Stable polling state */ | |
30 | ||
31 | DEBOUNCE_UNKNOWN = | |
32 | DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED, | |
33 | }; | |
34 | ||
35 | struct gpio_key_state { | |
36 | struct gpio_input_state *ds; | |
37 | uint8_t debounce; | |
38 | }; | |
39 | ||
40 | struct gpio_input_state { | |
41 | struct input_dev *input_dev; | |
42 | const struct gpio_event_input_info *info; | |
43 | struct hrtimer timer; | |
44 | int use_irq; | |
45 | int debounce_count; | |
46 | spinlock_t irq_lock; | |
420818f9 AH |
47 | struct gpio_key_state key_state[0]; |
48 | }; | |
49 | ||
50 | static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) | |
51 | { | |
52 | int i; | |
53 | int pressed; | |
54 | struct gpio_input_state *ds = | |
55 | container_of(timer, struct gpio_input_state, timer); | |
56 | unsigned gpio_flags = ds->info->flags; | |
57 | unsigned npolarity; | |
58 | int nkeys = ds->info->keymap_size; | |
59 | const struct gpio_event_direct_entry *key_entry; | |
60 | struct gpio_key_state *key_state; | |
61 | unsigned long irqflags; | |
62 | uint8_t debounce; | |
63 | ||
64 | #if 0 | |
65 | key_entry = kp->keys_info->keymap; | |
66 | key_state = kp->key_state; | |
67 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) | |
68 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | |
69 | gpio_read_detect_status(key_entry->gpio)); | |
70 | #endif | |
71 | key_entry = ds->info->keymap; | |
72 | key_state = ds->key_state; | |
73 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
74 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | |
75 | debounce = key_state->debounce; | |
76 | if (debounce & DEBOUNCE_WAIT_IRQ) | |
77 | continue; | |
78 | if (key_state->debounce & DEBOUNCE_UNSTABLE) { | |
79 | debounce = key_state->debounce = DEBOUNCE_UNKNOWN; | |
80 | enable_irq(gpio_to_irq(key_entry->gpio)); | |
81 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | |
82 | "(%d) continue debounce\n", | |
83 | ds->info->type, key_entry->code, | |
84 | i, key_entry->gpio); | |
85 | } | |
86 | npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); | |
87 | pressed = gpio_get_value(key_entry->gpio) ^ npolarity; | |
88 | if (debounce & DEBOUNCE_POLL) { | |
89 | if (pressed == !(debounce & DEBOUNCE_PRESSED)) { | |
90 | ds->debounce_count++; | |
91 | key_state->debounce = DEBOUNCE_UNKNOWN; | |
92 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | |
93 | pr_info("gpio_keys_scan_keys: key %x-" | |
94 | "%x, %d (%d) start debounce\n", | |
95 | ds->info->type, key_entry->code, | |
96 | i, key_entry->gpio); | |
97 | } | |
98 | continue; | |
99 | } | |
100 | if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { | |
101 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | |
102 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | |
103 | "(%d) debounce pressed 1\n", | |
104 | ds->info->type, key_entry->code, | |
105 | i, key_entry->gpio); | |
106 | key_state->debounce = DEBOUNCE_PRESSED; | |
107 | continue; | |
108 | } | |
109 | if (!pressed && (debounce & DEBOUNCE_PRESSED)) { | |
110 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | |
111 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | |
112 | "(%d) debounce pressed 0\n", | |
113 | ds->info->type, key_entry->code, | |
114 | i, key_entry->gpio); | |
115 | key_state->debounce = DEBOUNCE_NOTPRESSED; | |
116 | continue; | |
117 | } | |
118 | /* key is stable */ | |
119 | ds->debounce_count--; | |
120 | if (ds->use_irq) | |
121 | key_state->debounce |= DEBOUNCE_WAIT_IRQ; | |
122 | else | |
123 | key_state->debounce |= DEBOUNCE_POLL; | |
124 | if (gpio_flags & GPIOEDF_PRINT_KEYS) | |
125 | pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " | |
126 | "changed to %d\n", ds->info->type, | |
127 | key_entry->code, i, key_entry->gpio, pressed); | |
128 | input_event(ds->input_dev, ds->info->type, | |
129 | key_entry->code, pressed); | |
130 | } | |
131 | ||
132 | #if 0 | |
133 | key_entry = kp->keys_info->keymap; | |
134 | key_state = kp->key_state; | |
135 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | |
136 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | |
137 | gpio_read_detect_status(key_entry->gpio)); | |
138 | } | |
139 | #endif | |
140 | ||
141 | if (ds->debounce_count) | |
142 | hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL); | |
143 | else if (!ds->use_irq) | |
144 | hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL); | |
420818f9 AH |
145 | |
146 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
147 | ||
148 | return HRTIMER_NORESTART; | |
149 | } | |
150 | ||
151 | static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) | |
152 | { | |
153 | struct gpio_key_state *ks = dev_id; | |
154 | struct gpio_input_state *ds = ks->ds; | |
155 | int keymap_index = ks - ds->key_state; | |
156 | const struct gpio_event_direct_entry *key_entry; | |
157 | unsigned long irqflags; | |
158 | int pressed; | |
159 | ||
160 | if (!ds->use_irq) | |
161 | return IRQ_HANDLED; | |
162 | ||
163 | key_entry = &ds->info->keymap[keymap_index]; | |
164 | ||
165 | if (ds->info->debounce_time.tv64) { | |
166 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
167 | if (ks->debounce & DEBOUNCE_WAIT_IRQ) { | |
168 | ks->debounce = DEBOUNCE_UNKNOWN; | |
169 | if (ds->debounce_count++ == 0) { | |
420818f9 AH |
170 | hrtimer_start( |
171 | &ds->timer, ds->info->debounce_time, | |
172 | HRTIMER_MODE_REL); | |
173 | } | |
174 | if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | |
175 | pr_info("gpio_event_input_irq_handler: " | |
176 | "key %x-%x, %d (%d) start debounce\n", | |
177 | ds->info->type, key_entry->code, | |
178 | keymap_index, key_entry->gpio); | |
179 | } else { | |
180 | disable_irq(irq); | |
181 | ks->debounce = DEBOUNCE_UNSTABLE; | |
182 | } | |
183 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
184 | } else { | |
185 | pressed = gpio_get_value(key_entry->gpio) ^ | |
186 | !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); | |
187 | if (ds->info->flags & GPIOEDF_PRINT_KEYS) | |
188 | pr_info("gpio_event_input_irq_handler: key %x-%x, %d " | |
189 | "(%d) changed to %d\n", | |
190 | ds->info->type, key_entry->code, keymap_index, | |
191 | key_entry->gpio, pressed); | |
192 | input_event(ds->input_dev, ds->info->type, | |
193 | key_entry->code, pressed); | |
194 | } | |
195 | return IRQ_HANDLED; | |
196 | } | |
197 | ||
198 | static int gpio_event_input_request_irqs(struct gpio_input_state *ds) | |
199 | { | |
200 | int i; | |
201 | int err; | |
202 | unsigned int irq; | |
203 | unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | |
204 | ||
205 | for (i = 0; i < ds->info->keymap_size; i++) { | |
206 | err = irq = gpio_to_irq(ds->info->keymap[i].gpio); | |
207 | if (err < 0) | |
208 | goto err_gpio_get_irq_num_failed; | |
209 | err = request_irq(irq, gpio_event_input_irq_handler, | |
210 | req_flags, "gpio_keys", &ds->key_state[i]); | |
211 | if (err) { | |
212 | pr_err("gpio_event_input_request_irqs: request_irq " | |
213 | "failed for input %d, irq %d\n", | |
214 | ds->info->keymap[i].gpio, irq); | |
215 | goto err_request_irq_failed; | |
216 | } | |
217 | enable_irq_wake(irq); | |
218 | } | |
219 | return 0; | |
220 | ||
221 | for (i = ds->info->keymap_size - 1; i >= 0; i--) { | |
222 | free_irq(gpio_to_irq(ds->info->keymap[i].gpio), | |
223 | &ds->key_state[i]); | |
224 | err_request_irq_failed: | |
225 | err_gpio_get_irq_num_failed: | |
226 | ; | |
227 | } | |
228 | return err; | |
229 | } | |
230 | ||
231 | int gpio_event_input_func(struct input_dev *input_dev, | |
232 | struct gpio_event_info *info, void **data, int func) | |
233 | { | |
234 | int ret; | |
235 | int i; | |
236 | unsigned long irqflags; | |
237 | struct gpio_event_input_info *di; | |
238 | struct gpio_input_state *ds = *data; | |
239 | ||
240 | di = container_of(info, struct gpio_event_input_info, info); | |
241 | ||
242 | if (func == GPIO_EVENT_FUNC_SUSPEND) { | |
243 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
244 | if (ds->use_irq) | |
245 | for (i = 0; i < di->keymap_size; i++) | |
246 | disable_irq(gpio_to_irq(di->keymap[i].gpio)); | |
247 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
248 | hrtimer_cancel(&ds->timer); | |
249 | return 0; | |
250 | } | |
251 | if (func == GPIO_EVENT_FUNC_RESUME) { | |
252 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
253 | if (ds->use_irq) | |
254 | for (i = 0; i < di->keymap_size; i++) | |
255 | enable_irq(gpio_to_irq(di->keymap[i].gpio)); | |
256 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | |
257 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
258 | return 0; | |
259 | } | |
260 | ||
261 | if (func == GPIO_EVENT_FUNC_INIT) { | |
262 | if (ktime_to_ns(di->poll_time) <= 0) | |
263 | di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); | |
264 | ||
265 | *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * | |
266 | di->keymap_size, GFP_KERNEL); | |
267 | if (ds == NULL) { | |
268 | ret = -ENOMEM; | |
269 | pr_err("gpio_event_input_func: " | |
270 | "Failed to allocate private data\n"); | |
271 | goto err_ds_alloc_failed; | |
272 | } | |
273 | ds->debounce_count = di->keymap_size; | |
274 | ds->input_dev = input_dev; | |
275 | ds->info = di; | |
420818f9 AH |
276 | spin_lock_init(&ds->irq_lock); |
277 | ||
278 | for (i = 0; i < di->keymap_size; i++) { | |
279 | input_set_capability(input_dev, di->type, | |
280 | di->keymap[i].code); | |
281 | ds->key_state[i].ds = ds; | |
282 | ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; | |
283 | } | |
284 | ||
285 | for (i = 0; i < di->keymap_size; i++) { | |
286 | ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); | |
287 | if (ret) { | |
288 | pr_err("gpio_event_input_func: gpio_request " | |
289 | "failed for %d\n", di->keymap[i].gpio); | |
290 | goto err_gpio_request_failed; | |
291 | } | |
292 | ret = gpio_direction_input(di->keymap[i].gpio); | |
293 | if (ret) { | |
294 | pr_err("gpio_event_input_func: " | |
295 | "gpio_direction_input failed for %d\n", | |
296 | di->keymap[i].gpio); | |
297 | goto err_gpio_configure_failed; | |
298 | } | |
299 | } | |
300 | ||
301 | ret = gpio_event_input_request_irqs(ds); | |
302 | ||
303 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
304 | ds->use_irq = ret == 0; | |
305 | ||
306 | pr_info("GPIO Input Driver: Start gpio inputs for %s in %s " | |
307 | "mode\n", | |
308 | input_dev->name, ret == 0 ? "interrupt" : "polling"); | |
309 | ||
310 | hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | |
311 | ds->timer.function = gpio_event_input_timer_func; | |
312 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | |
313 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
314 | return 0; | |
315 | } | |
316 | ||
317 | ret = 0; | |
318 | spin_lock_irqsave(&ds->irq_lock, irqflags); | |
319 | hrtimer_cancel(&ds->timer); | |
320 | if (ds->use_irq) { | |
321 | for (i = di->keymap_size - 1; i >= 0; i--) { | |
322 | free_irq(gpio_to_irq(di->keymap[i].gpio), | |
323 | &ds->key_state[i]); | |
324 | } | |
325 | } | |
326 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | |
327 | ||
328 | for (i = di->keymap_size - 1; i >= 0; i--) { | |
329 | err_gpio_configure_failed: | |
330 | gpio_free(di->keymap[i].gpio); | |
331 | err_gpio_request_failed: | |
332 | ; | |
333 | } | |
420818f9 AH |
334 | kfree(ds); |
335 | err_ds_alloc_failed: | |
336 | return ret; | |
337 | } |