aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuotao Fu <l.fu@pengutronix.de>2010-06-10 15:05:23 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-06-10 15:33:59 -0400
commitfb76dd10b91146e9cefbb3cd4e6812c5a95ee43b (patch)
treea5f944375a2e7965ee61223a02455a20469483a9
parent1719ec4136035472d3e83a373908dd1b186dbc0b (diff)
Input: matrix_keypad - add support for clustered irq
This one adds support of a combined irq source for the whole matrix keypad. This can be useful if all rows and columns of the keypad are e.g. connected to a GPIO expander, which only has one interrupt line for all events on every single GPIO. Signed-off-by: Luotao Fu <l.fu@pengutronix.de> Acked-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/keyboard/matrix_keypad.c108
-rw-r--r--include/linux/input/matrix_keypad.h6
2 files changed, 86 insertions, 28 deletions
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b443e088fd3c..b02e4268e18f 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -37,6 +37,7 @@ struct matrix_keypad {
37 spinlock_t lock; 37 spinlock_t lock;
38 bool scan_pending; 38 bool scan_pending;
39 bool stopped; 39 bool stopped;
40 bool gpio_all_disabled;
40}; 41};
41 42
42/* 43/*
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
87 const struct matrix_keypad_platform_data *pdata = keypad->pdata; 88 const struct matrix_keypad_platform_data *pdata = keypad->pdata;
88 int i; 89 int i;
89 90
90 for (i = 0; i < pdata->num_row_gpios; i++) 91 if (pdata->clustered_irq > 0)
91 enable_irq(gpio_to_irq(pdata->row_gpios[i])); 92 enable_irq(pdata->clustered_irq);
93 else {
94 for (i = 0; i < pdata->num_row_gpios; i++)
95 enable_irq(gpio_to_irq(pdata->row_gpios[i]));
96 }
92} 97}
93 98
94static void disable_row_irqs(struct matrix_keypad *keypad) 99static void disable_row_irqs(struct matrix_keypad *keypad)
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
96 const struct matrix_keypad_platform_data *pdata = keypad->pdata; 101 const struct matrix_keypad_platform_data *pdata = keypad->pdata;
97 int i; 102 int i;
98 103
99 for (i = 0; i < pdata->num_row_gpios; i++) 104 if (pdata->clustered_irq > 0)
100 disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); 105 disable_irq_nosync(pdata->clustered_irq);
106 else {
107 for (i = 0; i < pdata->num_row_gpios; i++)
108 disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
109 }
101} 110}
102 111
103/* 112/*
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)
216} 225}
217 226
218#ifdef CONFIG_PM 227#ifdef CONFIG_PM
219static int matrix_keypad_suspend(struct device *dev) 228static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
220{ 229{
221 struct platform_device *pdev = to_platform_device(dev);
222 struct matrix_keypad *keypad = platform_get_drvdata(pdev);
223 const struct matrix_keypad_platform_data *pdata = keypad->pdata; 230 const struct matrix_keypad_platform_data *pdata = keypad->pdata;
231 unsigned int gpio;
224 int i; 232 int i;
225 233
226 matrix_keypad_stop(keypad->input_dev); 234 if (pdata->clustered_irq > 0) {
235 if (enable_irq_wake(pdata->clustered_irq) == 0)
236 keypad->gpio_all_disabled = true;
237 } else {
227 238
228 if (device_may_wakeup(&pdev->dev)) {
229 for (i = 0; i < pdata->num_row_gpios; i++) { 239 for (i = 0; i < pdata->num_row_gpios; i++) {
230 if (!test_bit(i, keypad->disabled_gpios)) { 240 if (!test_bit(i, keypad->disabled_gpios)) {
231 unsigned int gpio = pdata->row_gpios[i]; 241 gpio = pdata->row_gpios[i];
232 242
233 if (enable_irq_wake(gpio_to_irq(gpio)) == 0) 243 if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
234 __set_bit(i, keypad->disabled_gpios); 244 __set_bit(i, keypad->disabled_gpios);
235 } 245 }
236 } 246 }
237 } 247 }
238
239 return 0;
240} 248}
241 249
242static int matrix_keypad_resume(struct device *dev) 250static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
243{ 251{
244 struct platform_device *pdev = to_platform_device(dev);
245 struct matrix_keypad *keypad = platform_get_drvdata(pdev);
246 const struct matrix_keypad_platform_data *pdata = keypad->pdata; 252 const struct matrix_keypad_platform_data *pdata = keypad->pdata;
253 unsigned int gpio;
247 int i; 254 int i;
248 255
249 if (device_may_wakeup(&pdev->dev)) { 256 if (pdata->clustered_irq > 0) {
257 if (keypad->gpio_all_disabled) {
258 disable_irq_wake(pdata->clustered_irq);
259 keypad->gpio_all_disabled = false;
260 }
261 } else {
250 for (i = 0; i < pdata->num_row_gpios; i++) { 262 for (i = 0; i < pdata->num_row_gpios; i++) {
251 if (test_and_clear_bit(i, keypad->disabled_gpios)) { 263 if (test_and_clear_bit(i, keypad->disabled_gpios)) {
252 unsigned int gpio = pdata->row_gpios[i]; 264 gpio = pdata->row_gpios[i];
253
254 disable_irq_wake(gpio_to_irq(gpio)); 265 disable_irq_wake(gpio_to_irq(gpio));
255 } 266 }
256 } 267 }
257 } 268 }
269}
270
271static int matrix_keypad_suspend(struct device *dev)
272{
273 struct platform_device *pdev = to_platform_device(dev);
274 struct matrix_keypad *keypad = platform_get_drvdata(pdev);
275
276 matrix_keypad_stop(keypad->input_dev);
277
278 if (device_may_wakeup(&pdev->dev))
279 matrix_keypad_enable_wakeup(keypad);
280
281 return 0;
282}
283
284static int matrix_keypad_resume(struct device *dev)
285{
286 struct platform_device *pdev = to_platform_device(dev);
287 struct matrix_keypad *keypad = platform_get_drvdata(pdev);
288
289 if (device_may_wakeup(&pdev->dev))
290 matrix_keypad_disable_wakeup(keypad);
258 291
259 matrix_keypad_start(keypad->input_dev); 292 matrix_keypad_start(keypad->input_dev);
260 293
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
296 gpio_direction_input(pdata->row_gpios[i]); 329 gpio_direction_input(pdata->row_gpios[i]);
297 } 330 }
298 331
299 for (i = 0; i < pdata->num_row_gpios; i++) { 332 if (pdata->clustered_irq > 0) {
300 err = request_irq(gpio_to_irq(pdata->row_gpios[i]), 333 err = request_irq(pdata->clustered_irq,
301 matrix_keypad_interrupt, 334 matrix_keypad_interrupt,
302 IRQF_DISABLED | 335 pdata->clustered_irq_flags,
303 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
304 "matrix-keypad", keypad); 336 "matrix-keypad", keypad);
305 if (err) { 337 if (err) {
306 dev_err(&pdev->dev, 338 dev_err(&pdev->dev,
307 "Unable to acquire interrupt for GPIO line %i\n", 339 "Unable to acquire clustered interrupt\n");
308 pdata->row_gpios[i]); 340 goto err_free_rows;
309 goto err_free_irqs; 341 }
342 } else {
343 for (i = 0; i < pdata->num_row_gpios; i++) {
344 err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
345 matrix_keypad_interrupt,
346 IRQF_DISABLED |
347 IRQF_TRIGGER_RISING |
348 IRQF_TRIGGER_FALLING,
349 "matrix-keypad", keypad);
350 if (err) {
351 dev_err(&pdev->dev,
352 "Unable to acquire interrupt "
353 "for GPIO line %i\n",
354 pdata->row_gpios[i]);
355 goto err_free_irqs;
356 }
310 } 357 }
311 } 358 }
312 359
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
418 465
419 device_init_wakeup(&pdev->dev, 0); 466 device_init_wakeup(&pdev->dev, 0);
420 467
421 for (i = 0; i < pdata->num_row_gpios; i++) { 468 if (pdata->clustered_irq > 0) {
422 free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); 469 free_irq(pdata->clustered_irq, keypad);
423 gpio_free(pdata->row_gpios[i]); 470 } else {
471 for (i = 0; i < pdata->num_row_gpios; i++)
472 free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
424 } 473 }
425 474
475 for (i = 0; i < pdata->num_row_gpios; i++)
476 gpio_free(pdata->row_gpios[i]);
477
426 for (i = 0; i < pdata->num_col_gpios; i++) 478 for (i = 0; i < pdata->num_col_gpios; i++)
427 gpio_free(pdata->col_gpios[i]); 479 gpio_free(pdata->col_gpios[i]);
428 480
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index c964cd7f436a..80352ad6581a 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -41,6 +41,9 @@ struct matrix_keymap_data {
41 * @col_scan_delay_us: delay, measured in microseconds, that is 41 * @col_scan_delay_us: delay, measured in microseconds, that is
42 * needed before we can keypad after activating column gpio 42 * needed before we can keypad after activating column gpio
43 * @debounce_ms: debounce interval in milliseconds 43 * @debounce_ms: debounce interval in milliseconds
44 * @clustered_irq: may be specified if interrupts of all row/column GPIOs
45 * are bundled to one single irq
46 * @clustered_irq_flags: flags that are needed for the clustered irq
44 * @active_low: gpio polarity 47 * @active_low: gpio polarity
45 * @wakeup: controls whether the device should be set up as wakeup 48 * @wakeup: controls whether the device should be set up as wakeup
46 * source 49 * source
@@ -63,6 +66,9 @@ struct matrix_keypad_platform_data {
63 /* key debounce interval in milli-second */ 66 /* key debounce interval in milli-second */
64 unsigned int debounce_ms; 67 unsigned int debounce_ms;
65 68
69 unsigned int clustered_irq;
70 unsigned int clustered_irq_flags;
71
66 bool active_low; 72 bool active_low;
67 bool wakeup; 73 bool wakeup;
68 bool no_autorepeat; 74 bool no_autorepeat;