aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/keyboard/Kconfig9
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/imx_keypad.c594
3 files changed, 604 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c72283c6916f..616a3916d187 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -292,6 +292,15 @@ config KEYBOARD_MAX7359
292 To compile this driver as a module, choose M here: the 292 To compile this driver as a module, choose M here: the
293 module will be called max7359_keypad. 293 module will be called max7359_keypad.
294 294
295config KEYBOARD_IMX
296 tristate "IMX keypad support"
297 depends on ARCH_MXC
298 help
299 Enable support for IMX keypad port.
300
301 To compile this driver as a module, choose M here: the
302 module will be called imx_keypad.
303
295config KEYBOARD_NEWTON 304config KEYBOARD_NEWTON
296 tristate "Newton keyboard" 305 tristate "Newton keyboard"
297 select SERIO 306 select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 78654ef65206..706c6b5ed5f4 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
17obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o 17obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
18obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o 18obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
19obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o 19obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
20obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
20obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o 21obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
21obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o 22obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
22obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o 23obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
new file mode 100644
index 000000000000..2ee5b798024d
--- /dev/null
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -0,0 +1,594 @@
1/*
2 * Driver for the IMX keypad port.
3 * Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * <<Power management needs to be implemented>>.
10 */
11
12#include <linux/clk.h>
13#include <linux/delay.h>
14#include <linux/device.h>
15#include <linux/err.h>
16#include <linux/init.h>
17#include <linux/input/matrix_keypad.h>
18#include <linux/interrupt.h>
19#include <linux/io.h>
20#include <linux/jiffies.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/platform_device.h>
24#include <linux/timer.h>
25
26/*
27 * Keypad Controller registers (halfword)
28 */
29#define KPCR 0x00 /* Keypad Control Register */
30
31#define KPSR 0x02 /* Keypad Status Register */
32#define KBD_STAT_KPKD (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */
33#define KBD_STAT_KPKR (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */
34#define KBD_STAT_KDSC (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/
35#define KBD_STAT_KRSS (0x1 << 3) /* Key Release Synch Status bit (w1c)*/
36#define KBD_STAT_KDIE (0x1 << 8) /* Key Depress Interrupt Enable Status bit */
37#define KBD_STAT_KRIE (0x1 << 9) /* Key Release Interrupt Enable */
38#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
39
40#define KDDR 0x04 /* Keypad Data Direction Register */
41#define KPDR 0x06 /* Keypad Data Register */
42
43#define MAX_MATRIX_KEY_ROWS 8
44#define MAX_MATRIX_KEY_COLS 8
45#define MATRIX_ROW_SHIFT 3
46
47#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
48
49struct imx_keypad {
50
51 struct clk *clk;
52 struct input_dev *input_dev;
53 void __iomem *mmio_base;
54
55 int irq;
56 struct timer_list check_matrix_timer;
57
58 /*
59 * The matrix is stable only if no changes are detected after
60 * IMX_KEYPAD_SCANS_FOR_STABILITY scans
61 */
62#define IMX_KEYPAD_SCANS_FOR_STABILITY 3
63 int stable_count;
64
65 bool enabled;
66
67 /* Masks for enabled rows/cols */
68 unsigned short rows_en_mask;
69 unsigned short cols_en_mask;
70
71 unsigned short keycodes[MAX_MATRIX_KEY_NUM];
72
73 /*
74 * Matrix states:
75 * -stable: achieved after a complete debounce process.
76 * -unstable: used in the debouncing process.
77 */
78 unsigned short matrix_stable_state[MAX_MATRIX_KEY_COLS];
79 unsigned short matrix_unstable_state[MAX_MATRIX_KEY_COLS];
80};
81
82/* Scan the matrix and return the new state in *matrix_volatile_state. */
83static void imx_keypad_scan_matrix(struct imx_keypad *keypad,
84 unsigned short *matrix_volatile_state)
85{
86 int col;
87 unsigned short reg_val;
88
89 for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
90 if ((keypad->cols_en_mask & (1 << col)) == 0)
91 continue;
92 /*
93 * Discharge keypad capacitance:
94 * 2. write 1s on column data.
95 * 3. configure columns as totem-pole to discharge capacitance.
96 * 4. configure columns as open-drain.
97 */
98 reg_val = readw(keypad->mmio_base + KPDR);
99 reg_val |= 0xff00;
100 writew(reg_val, keypad->mmio_base + KPDR);
101
102 reg_val = readw(keypad->mmio_base + KPCR);
103 reg_val &= ~((keypad->cols_en_mask & 0xff) << 8);
104 writew(reg_val, keypad->mmio_base + KPCR);
105
106 udelay(2);
107
108 reg_val = readw(keypad->mmio_base + KPCR);
109 reg_val |= (keypad->cols_en_mask & 0xff) << 8;
110 writew(reg_val, keypad->mmio_base + KPCR);
111
112 /*
113 * 5. Write a single column to 0, others to 1.
114 * 6. Sample row inputs and save data.
115 * 7. Repeat steps 2 - 6 for remaining columns.
116 */
117 reg_val = readw(keypad->mmio_base + KPDR);
118 reg_val &= ~(1 << (8 + col));
119 writew(reg_val, keypad->mmio_base + KPDR);
120
121 /*
122 * Delay added to avoid propagating the 0 from column to row
123 * when scanning.
124 */
125 udelay(5);
126
127 /*
128 * 1s in matrix_volatile_state[col] means key pressures
129 * throw data from non enabled rows.
130 */
131 reg_val = readw(keypad->mmio_base + KPDR);
132 matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask;
133 }
134
135 /*
136 * Return in standby mode:
137 * 9. write 0s to columns
138 */
139 reg_val = readw(keypad->mmio_base + KPDR);
140 reg_val &= 0x00ff;
141 writew(reg_val, keypad->mmio_base + KPDR);
142}
143
144/*
145 * Compare the new matrix state (volatile) with the stable one stored in
146 * keypad->matrix_stable_state and fire events if changes are detected.
147 */
148static void imx_keypad_fire_events(struct imx_keypad *keypad,
149 unsigned short *matrix_volatile_state)
150{
151 struct input_dev *input_dev = keypad->input_dev;
152 int row, col;
153
154 for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
155 unsigned short bits_changed;
156 int code;
157
158 if ((keypad->cols_en_mask & (1 << col)) == 0)
159 continue; /* Column is not enabled */
160
161 bits_changed = keypad->matrix_stable_state[col] ^
162 matrix_volatile_state[col];
163
164 if (bits_changed == 0)
165 continue; /* Column does not contain changes */
166
167 for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
168 if ((keypad->rows_en_mask & (1 << row)) == 0)
169 continue; /* Row is not enabled */
170 if ((bits_changed & (1 << row)) == 0)
171 continue; /* Row does not contain changes */
172
173 code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
174 input_event(input_dev, EV_MSC, MSC_SCAN, code);
175 input_report_key(input_dev, keypad->keycodes[code],
176 matrix_volatile_state[col] & (1 << row));
177 dev_dbg(&input_dev->dev, "Event code: %d, val: %d",
178 keypad->keycodes[code],
179 matrix_volatile_state[col] & (1 << row));
180 }
181 }
182 input_sync(input_dev);
183}
184
185/*
186 * imx_keypad_check_for_events is the timer handler.
187 */
188static void imx_keypad_check_for_events(unsigned long data)
189{
190 struct imx_keypad *keypad = (struct imx_keypad *) data;
191 unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
192 unsigned short reg_val;
193 bool state_changed, is_zero_matrix;
194 int i;
195
196 memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state));
197
198 imx_keypad_scan_matrix(keypad, matrix_volatile_state);
199
200 state_changed = false;
201 for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
202 if ((keypad->cols_en_mask & (1 << i)) == 0)
203 continue;
204
205 if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) {
206 state_changed = true;
207 break;
208 }
209 }
210
211 /*
212 * If the matrix state is changed from the previous scan
213 * (Re)Begin the debouncing process, saving the new state in
214 * keypad->matrix_unstable_state.
215 * else
216 * Increase the count of number of scans with a stable state.
217 */
218 if (state_changed) {
219 memcpy(keypad->matrix_unstable_state, matrix_volatile_state,
220 sizeof(matrix_volatile_state));
221 keypad->stable_count = 0;
222 } else
223 keypad->stable_count++;
224
225 /*
226 * If the matrix is not as stable as we want reschedule scan
227 * in the near future.
228 */
229 if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
230 mod_timer(&keypad->check_matrix_timer,
231 jiffies + msecs_to_jiffies(10));
232 return;
233 }
234
235 /*
236 * If the matrix state is stable, fire the events and save the new
237 * stable state. Note, if the matrix is kept stable for longer
238 * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all
239 * events have already been generated.
240 */
241 if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
242 imx_keypad_fire_events(keypad, matrix_volatile_state);
243
244 memcpy(keypad->matrix_stable_state, matrix_volatile_state,
245 sizeof(matrix_volatile_state));
246 }
247
248 is_zero_matrix = true;
249 for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
250 if (matrix_volatile_state[i] != 0) {
251 is_zero_matrix = false;
252 break;
253 }
254 }
255
256
257 if (is_zero_matrix) {
258 /*
259 * All keys have been released. Enable only the KDI
260 * interrupt for future key presses (clear the KDI
261 * status bit and its sync chain before that).
262 */
263 reg_val = readw(keypad->mmio_base + KPSR);
264 reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
265 writew(reg_val, keypad->mmio_base + KPSR);
266
267 reg_val = readw(keypad->mmio_base + KPSR);
268 reg_val |= KBD_STAT_KDIE;
269 reg_val &= ~KBD_STAT_KRIE;
270 writew(reg_val, keypad->mmio_base + KPSR);
271 } else {
272 /*
273 * Some keys are still pressed. Schedule a rescan in
274 * attempt to detect multiple key presses and enable
275 * the KRI interrupt to react quickly to key release
276 * event.
277 */
278 mod_timer(&keypad->check_matrix_timer,
279 jiffies + msecs_to_jiffies(60));
280
281 reg_val = readw(keypad->mmio_base + KPSR);
282 reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
283 writew(reg_val, keypad->mmio_base + KPSR);
284
285 reg_val = readw(keypad->mmio_base + KPSR);
286 reg_val |= KBD_STAT_KRIE;
287 reg_val &= ~KBD_STAT_KDIE;
288 writew(reg_val, keypad->mmio_base + KPSR);
289 }
290}
291
292static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
293{
294 struct imx_keypad *keypad = dev_id;
295 unsigned short reg_val;
296
297 reg_val = readw(keypad->mmio_base + KPSR);
298
299 /* Disable both interrupt types */
300 reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
301 /* Clear interrupts status bits */
302 reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
303 writew(reg_val, keypad->mmio_base + KPSR);
304
305 if (keypad->enabled) {
306 /* The matrix is supposed to be changed */
307 keypad->stable_count = 0;
308
309 /* Schedule the scanning procedure near in the future */
310 mod_timer(&keypad->check_matrix_timer,
311 jiffies + msecs_to_jiffies(2));
312 }
313
314 return IRQ_HANDLED;
315}
316
317static void imx_keypad_config(struct imx_keypad *keypad)
318{
319 unsigned short reg_val;
320
321 /*
322 * Include enabled rows in interrupt generation (KPCR[7:0])
323 * Configure keypad columns as open-drain (KPCR[15:8])
324 */
325 reg_val = readw(keypad->mmio_base + KPCR);
326 reg_val |= keypad->rows_en_mask & 0xff; /* rows */
327 reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */
328 writew(reg_val, keypad->mmio_base + KPCR);
329
330 /* Write 0's to KPDR[15:8] (Colums) */
331 reg_val = readw(keypad->mmio_base + KPDR);
332 reg_val &= 0x00ff;
333 writew(reg_val, keypad->mmio_base + KPDR);
334
335 /* Configure columns as output, rows as input (KDDR[15:0]) */
336 writew(0xff00, keypad->mmio_base + KDDR);
337
338 /*
339 * Clear Key Depress and Key Release status bit.
340 * Clear both synchronizer chain.
341 */
342 reg_val = readw(keypad->mmio_base + KPSR);
343 reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD |
344 KBD_STAT_KDSC | KBD_STAT_KRSS;
345 writew(reg_val, keypad->mmio_base + KPSR);
346
347 /* Enable KDI and disable KRI (avoid false release events). */
348 reg_val |= KBD_STAT_KDIE;
349 reg_val &= ~KBD_STAT_KRIE;
350 writew(reg_val, keypad->mmio_base + KPSR);
351}
352
353static void imx_keypad_inhibit(struct imx_keypad *keypad)
354{
355 unsigned short reg_val;
356
357 /* Inhibit KDI and KRI interrupts. */
358 reg_val = readw(keypad->mmio_base + KPSR);
359 reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
360 writew(reg_val, keypad->mmio_base + KPSR);
361
362 /* Colums as open drain and disable all rows */
363 writew(0xff00, keypad->mmio_base + KPCR);
364}
365
366static void imx_keypad_close(struct input_dev *dev)
367{
368 struct imx_keypad *keypad = input_get_drvdata(dev);
369
370 dev_dbg(&dev->dev, ">%s\n", __func__);
371
372 /* Mark keypad as being inactive */
373 keypad->enabled = false;
374 synchronize_irq(keypad->irq);
375 del_timer_sync(&keypad->check_matrix_timer);
376
377 imx_keypad_inhibit(keypad);
378
379 /* Disable clock unit */
380 clk_disable(keypad->clk);
381}
382
383static int imx_keypad_open(struct input_dev *dev)
384{
385 struct imx_keypad *keypad = input_get_drvdata(dev);
386
387 dev_dbg(&dev->dev, ">%s\n", __func__);
388
389 /* We became active from now */
390 keypad->enabled = true;
391
392 /* Enable the kpp clock */
393 clk_enable(keypad->clk);
394 imx_keypad_config(keypad);
395
396 /* Sanity control, not all the rows must be actived now. */
397 if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
398 dev_err(&dev->dev,
399 "too many keys pressed, control pins initialisation\n");
400 goto open_err;
401 }
402
403 return 0;
404
405open_err:
406 imx_keypad_close(dev);
407 return -EIO;
408}
409
410static int __devinit imx_keypad_probe(struct platform_device *pdev)
411{
412 const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
413 struct imx_keypad *keypad;
414 struct input_dev *input_dev;
415 struct resource *res;
416 int irq, error, i;
417
418 if (keymap_data == NULL) {
419 dev_err(&pdev->dev, "no keymap defined\n");
420 return -EINVAL;
421 }
422
423 irq = platform_get_irq(pdev, 0);
424 if (irq < 0) {
425 dev_err(&pdev->dev, "no irq defined in platform data\n");
426 return -EINVAL;
427 }
428
429 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
430 if (res == NULL) {
431 dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
432 return -EINVAL;
433 }
434
435 res = request_mem_region(res->start, resource_size(res), pdev->name);
436 if (res == NULL) {
437 dev_err(&pdev->dev, "failed to request I/O memory\n");
438 return -EBUSY;
439 }
440
441 input_dev = input_allocate_device();
442 if (!input_dev) {
443 dev_err(&pdev->dev, "failed to allocate the input device\n");
444 error = -ENOMEM;
445 goto failed_rel_mem;
446 }
447
448 keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
449 if (!keypad) {
450 dev_err(&pdev->dev, "not enough memory for driver data\n");
451 error = -ENOMEM;
452 goto failed_free_input;
453 }
454
455 keypad->input_dev = input_dev;
456 keypad->irq = irq;
457 keypad->stable_count = 0;
458
459 setup_timer(&keypad->check_matrix_timer,
460 imx_keypad_check_for_events, (unsigned long) keypad);
461
462 keypad->mmio_base = ioremap(res->start, resource_size(res));
463 if (keypad->mmio_base == NULL) {
464 dev_err(&pdev->dev, "failed to remap I/O memory\n");
465 error = -ENOMEM;
466 goto failed_free_priv;
467 }
468
469 keypad->clk = clk_get(&pdev->dev, "kpp");
470 if (IS_ERR(keypad->clk)) {
471 dev_err(&pdev->dev, "failed to get keypad clock\n");
472 error = PTR_ERR(keypad->clk);
473 goto failed_unmap;
474 }
475
476 /* Search for rows and cols enabled */
477 for (i = 0; i < keymap_data->keymap_size; i++) {
478 keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
479 keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
480 }
481
482 if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
483 keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
484 dev_err(&pdev->dev,
485 "invalid key data (too many rows or colums)\n");
486 error = -EINVAL;
487 goto failed_clock_put;
488 }
489 dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
490 dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
491
492 /* Init the Input device */
493 input_dev->name = pdev->name;
494 input_dev->id.bustype = BUS_HOST;
495 input_dev->dev.parent = &pdev->dev;
496 input_dev->open = imx_keypad_open;
497 input_dev->close = imx_keypad_close;
498 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
499 input_dev->keycode = keypad->keycodes;
500 input_dev->keycodesize = sizeof(keypad->keycodes[0]);
501 input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
502
503 matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
504 keypad->keycodes, input_dev->keybit);
505
506 input_set_capability(input_dev, EV_MSC, MSC_SCAN);
507 input_set_drvdata(input_dev, keypad);
508
509 /* Ensure that the keypad will stay dormant until opened */
510 imx_keypad_inhibit(keypad);
511
512 error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
513 pdev->name, keypad);
514 if (error) {
515 dev_err(&pdev->dev, "failed to request IRQ\n");
516 goto failed_clock_put;
517 }
518
519 /* Register the input device */
520 error = input_register_device(input_dev);
521 if (error) {
522 dev_err(&pdev->dev, "failed to register input device\n");
523 goto failed_free_irq;
524 }
525
526 platform_set_drvdata(pdev, keypad);
527 device_init_wakeup(&pdev->dev, 1);
528
529 return 0;
530
531failed_free_irq:
532 free_irq(irq, pdev);
533failed_clock_put:
534 clk_put(keypad->clk);
535failed_unmap:
536 iounmap(keypad->mmio_base);
537failed_free_priv:
538 kfree(keypad);
539failed_free_input:
540 input_free_device(input_dev);
541failed_rel_mem:
542 release_mem_region(res->start, resource_size(res));
543 return error;
544}
545
546static int __devexit imx_keypad_remove(struct platform_device *pdev)
547{
548 struct imx_keypad *keypad = platform_get_drvdata(pdev);
549 struct resource *res;
550
551 dev_dbg(&pdev->dev, ">%s\n", __func__);
552
553 platform_set_drvdata(pdev, NULL);
554
555 input_unregister_device(keypad->input_dev);
556
557 free_irq(keypad->irq, keypad);
558 clk_put(keypad->clk);
559
560 iounmap(keypad->mmio_base);
561 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
562 release_mem_region(res->start, resource_size(res));
563
564 kfree(keypad);
565
566 return 0;
567}
568
569static struct platform_driver imx_keypad_driver = {
570 .driver = {
571 .name = "imx-keypad",
572 .owner = THIS_MODULE,
573 },
574 .probe = imx_keypad_probe,
575 .remove = __devexit_p(imx_keypad_remove),
576};
577
578static int __init imx_keypad_init(void)
579{
580 return platform_driver_register(&imx_keypad_driver);
581}
582
583static void __exit imx_keypad_exit(void)
584{
585 platform_driver_unregister(&imx_keypad_driver);
586}
587
588module_init(imx_keypad_init);
589module_exit(imx_keypad_exit);
590
591MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
592MODULE_DESCRIPTION("IMX Keypad Port Driver");
593MODULE_LICENSE("GPL v2");
594MODULE_ALIAS("platform:imx-keypad");