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