]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/input/keyboard/omap-keypad.c
h63xx: button and joypad support
[linux-2.6-omap-h63xx.git] / drivers / input / keyboard / omap-keypad.c
1 /*
2  * linux/drivers/char/omap-keypad.c
3  *
4  * OMAP Keypad Driver
5  *
6  * Copyright (C) 2003 Nokia Corporation
7  * Written by Timo Teräs <ext-timo.teras@nokia.com>
8  *
9  * Added support for H2 & H3 Keypad
10  * Copyright (C) 2004 Texas Instruments
11  *
12  * Added support for keypad and joypad in HP iPAQ h63xx series of devices.
13  * Copyright (C) 2005 Mika Laitio
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28  */
29
30 #include <linux/module.h>
31 #include <linux/init.h>
32 #include <linux/interrupt.h>
33 #include <linux/types.h>
34 #include <linux/input.h>
35 #include <linux/kernel.h>
36 #include <linux/delay.h>
37 #include <linux/platform_device.h>
38 #include <linux/mutex.h>
39 #include <asm/arch/irqs.h>
40 #include <asm/arch/gpio.h>
41 #include <asm/arch/hardware.h>
42 #include <asm/arch/keypad.h>
43 #include <asm/arch/menelaus.h>
44 #include <asm/io.h>
45 #include <asm/errno.h>
46 #include <asm/mach-types.h>
47 #include <asm/arch/mux.h>
48
49 #undef NEW_BOARD_LEARNING_MODE
50 //#define NEW_BOARD_LEARNING_MODE 1
51
52 /*
53  * Following 5 keypad events are not really sent to userspace. 
54  * Instead if the good combination of them is sent, then that is send.
55  * (up, right, down, left, enter)
56  */
57 #define _H6300_JOYPAD_UP_RIGHT          1       // 00001
58 #define _H6300_JOYPAD_DOWN_RIGHT        2       // 00010
59 #define _h6300_JOYPAD_DOWN_LEFT         4       // 00100
60 #define _h6300_JOYPAD_UP_LEFT           8       // 01000
61 #define _H6300_JOYPAD_KEY_OK            16      // 10000
62 #define _H6300_JOYPAD_REPORT_COLUMN     4
63
64 static void omap_kp_tasklet(unsigned long);
65 static void omap_kp_timer(unsigned long);
66
67 static unsigned char keypad_state[8];
68 static DEFINE_MUTEX(kp_enable_mutex);
69 static int kp_enable = 1;
70 static int kp_cur_group = -1;
71
72 static int prevJoypadKeycodePressEmulated;
73
74 struct omap_kp {
75         struct input_dev *input;
76         struct timer_list timer;
77         int irq;
78         unsigned int rows;
79         unsigned int cols;
80 };
81
82 DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
83
84 static int *keymap;
85 static unsigned int *row_gpios;
86 static unsigned int *col_gpios;
87
88 #ifdef CONFIG_ARCH_OMAP2
89 static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
90 {
91         int col;
92         for (col = 0; col < omap_kp->cols; col++) {
93                 if (value & (1 << col))
94                         omap_set_gpio_dataout(col_gpios[col], 1);
95                 else
96                         omap_set_gpio_dataout(col_gpios[col], 0);
97         }
98 }
99
100 static u8 get_row_gpio_val(struct omap_kp *omap_kp)
101 {
102         int row;
103         u8 value = 0;
104
105         for (row = 0; row < omap_kp->rows; row++) {
106                 if (omap_get_gpio_datain(row_gpios[row]))
107                         value |= (1 << row);
108         }
109         return value;
110 }
111 #else
112 #define         set_col_gpio_val(x, y)  do {} while (0)
113 #define         get_row_gpio_val(x)     0
114 #endif
115
116 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
117                                      struct pt_regs *regs)
118 {
119         struct omap_kp *omap_kp = dev_id;
120
121         /* disable keyboard interrupt and schedule for handling */
122         if (cpu_is_omap24xx()) {
123                 int i;
124                 for (i = 0; i < omap_kp->rows; i++)
125                         disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
126         } else {
127                 /* disable keyboard interrupt and schedule for handling */
128                 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
129         }
130
131         tasklet_schedule(&kp_tasklet);
132
133         return IRQ_HANDLED;
134 }
135
136 static void omap_kp_timer(unsigned long data)
137 {
138         tasklet_schedule(&kp_tasklet);
139 }
140
141 static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
142 {
143         int col = 0;
144
145         /* read the keypad status */
146         if (cpu_is_omap24xx()) {
147                 int i;
148                 for (i = 0; i < omap_kp->rows; i++)
149                         disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
150         } else {
151                 /* disable keyboard interrupt and schedule for handling */
152                 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
153         }
154         if (!cpu_is_omap24xx()) {
155                 /* read the keypad status */
156                 omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
157                 for (col = 0; col < omap_kp->cols; col++) {
158                         omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
159
160                         if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3() || machine_is_omap_h6300()) {
161                                 udelay(9);
162                         } else {
163                                 udelay(4);
164                         }
165                         state[col] = ~omap_readw(OMAP_MPUIO_BASE + OMAP_MPUIO_KBR_LATCH) & 0xff;
166                 }
167                 omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
168                 udelay(2);
169         } else {
170                 /* read the keypad status */
171                 for (col = 0; col < omap_kp->cols; col++) {
172                         set_col_gpio_val(omap_kp, ~(1 << col));
173                         state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
174                 }
175                 set_col_gpio_val(omap_kp, 0);
176         }
177 }
178
179 static inline int omap_kp_find_key(int col, int row)
180 {
181         int i, key;
182
183         key = KEY(col, row, 0);
184         for (i = 0; keymap[i] != 0; i++)
185                 if ((keymap[i] & 0xff000000) == key)
186                         return keymap[i] & 0x00ffffff;
187         return -1;
188 }
189
190 int is_key_down(unsigned char new_state[],
191                 int col,
192                 int row)
193 {
194         return (new_state[col] & (1 << row)) ? 1 : 0;
195 }
196
197 static void omap_kp_tasklet(unsigned long data)
198 {
199         struct omap_kp *omap_kp_data = (struct omap_kp *) data;
200         unsigned char new_state[8], changed, key_down = 0;
201         int col, row;
202         int spurious = 0;
203         int report_key, report_col, report_row, joypad_checked; // h6300-joypad specific variables
204
205         /* check for any changes */
206         omap_kp_scan_keypad(omap_kp_data, new_state);
207
208         /* check for changes and print those */
209         joypad_checked  = 0;
210         for (col = 0; col < omap_kp_data->cols; col++) {
211                 changed = new_state[col] ^ keypad_state[col];
212                 key_down |= new_state[col];
213                 if (changed == 0)
214                         continue;
215
216                 for (row = 0; row < omap_kp_data->rows; row++) {
217                         int key;
218                         if (!(changed & (1 << row)))
219                                 continue;
220 #ifdef NEW_BOARD_LEARNING_MODE
221                         printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, row, (new_state[col] & (1 << row)) ? "pressed" : "released");
222 #else
223                         key = omap_kp_find_key(col, row);
224                         if (key < 0) {
225                                 printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n",
226                                        col, row);
227                                 /* We scan again after a couple of seconds */
228                                 spurious = 1;
229                                 continue;
230                         }
231                         if (machine_is_omap_h6300() && 
232                            ((col == 1) || (col == _H6300_JOYPAD_REPORT_COLUMN)))
233                         {
234                                 if (col == _H6300_JOYPAD_REPORT_COLUMN)
235                                 {
236                                         continue;
237                                 }
238                                 if ((joypad_checked == 0) &&
239                                     ((key == _H6300_JOYPAD_KEY_OK) ||
240                                      (key == _h6300_JOYPAD_UP_LEFT) ||
241                                      (key == _H6300_JOYPAD_UP_RIGHT) ||
242                                      (key == _H6300_JOYPAD_DOWN_RIGHT) ||
243                                      (key == _h6300_JOYPAD_DOWN_LEFT)))
244                                 {
245                                         if (is_key_down(new_state, col, row))
246                                         {
247                                                 /*
248                                                  * only enter pressed
249                                                  * 1 0 0 _H6300_JOYPAD_KEY_OK 0 0
250                                                  * --> 100100 == 36
251                                                  */
252                                                  if (new_state[1] == 36)
253                                                  {
254                                                         joypad_checked  = 1;
255                                                         prevJoypadKeycodePressEmulated  = KEY_ENTER;
256                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 48;   //110000
257                                                         report_key      = prevJoypadKeycodePressEmulated;
258                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
259                                                         report_row      = 4;
260                                                         input_report_key(omap_kp_data->input,
261                                                                         report_key,
262                                                                         new_state[report_col] & (1 << report_row));
263                                                  }                                              
264                                                 /*
265                                                  * enter, up_left and up_right sensors pressed.
266                                                  * 1 _H6300_JOYPAD_UP_RIGHT 0 _H6300_JOYPAD_KEY_OK 0 _h6300_JOYPAD_UP_LEFT
267                                                  * --> 110101 == 53
268                                                  * OR
269                                                  * 1 KEY_UP_RIGHT 0 0 0 _h6300_JOYPAD_UP_LEFT
270                                                  * --> 110001 == 42
271                                                  * --> move to up
272                                                  */
273                                                 else if ((new_state[1] == 53) ||
274                                                          (new_state[1] == 49))
275                                                 {
276                                                         joypad_checked  = 1;
277                                                         prevJoypadKeycodePressEmulated  = KEY_UP;
278                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 40;   //101000
279                                                         report_key      = prevJoypadKeycodePressEmulated;
280                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
281                                                         report_row      = 3;
282                                                         input_report_key(omap_kp_data->input,
283                                                                         report_key,
284                                                                         new_state[report_col] & (1 << report_row));
285                                                 }
286                                                 /*
287                                                  * enter, down_left and down_right sensors pressed
288                                                  * --> 101110 == 46
289                                                  * OR
290                                                  * down_left and down_right
291                                                  * -->101010 == 42
292                                                  * --> move to down
293                                                  */
294                                                 else if ((new_state[1] == 46) ||
295                                                          (new_state[1] == 42))
296                                                 {
297                                                         joypad_checked  = 1;
298                                                         prevJoypadKeycodePressEmulated  = KEY_DOWN;
299                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 34;   //100010
300                                                         report_key      = prevJoypadKeycodePressEmulated;
301                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
302                                                         report_row      = 1;
303                                                         input_report_key(omap_kp_data->input,
304                                                                         report_key,
305                                                                         new_state[report_col] & (1 << report_row));
306                                                 }                                                                                               
307                                                 /*
308                                                  * enter, up_right and down_right sensors pressed
309                                                  * --> 111100 == 60
310                                                  * or
311                                                  * down_right and up_right
312                                                  * --> 111000 == 56
313                                                  * --> move to right
314                                                  */
315                                                 else if ((new_state[1] == 60) ||
316                                                          (new_state[1] == 56))
317                                                 {
318                                                         joypad_checked  = 1;
319                                                         prevJoypadKeycodePressEmulated  = KEY_RIGHT;
320                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 33;   //100001
321                                                         report_key      = prevJoypadKeycodePressEmulated;
322                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
323                                                         report_row      = 0;
324                                                         input_report_key(omap_kp_data->input,
325                                                                         report_key,
326                                                                         new_state[report_col] & (1 << report_row));
327                                                 }
328                                                 /*
329                                                  * enter, up_left and down_left sensors pressed
330                                                  * --> 100111 == 39
331                                                  * or up_left and down_left
332                                                  * --> 100011 == 35
333                                                  * --> move to left
334                                                  */
335                                                 else if ((new_state[1] == 39) ||
336                                                          (new_state[1] == 35))
337                                                 {
338                                                         joypad_checked  = 1;
339                                                         prevJoypadKeycodePressEmulated  = KEY_LEFT;
340                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 36;   //100100
341                                                         report_key      = prevJoypadKeycodePressEmulated;
342                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
343                                                         report_row      = 2;
344                                                         input_report_key(omap_kp_data->input,
345                                                                         report_key,
346                                                                         new_state[report_col] & (1 << report_row));
347                                                 }
348                                                 else
349                                                 {
350                                                         //printk("missed new_state = %d\n", new_state[1]);
351                                                 }
352                                         }
353                                         else
354                                         {
355                                                 if (prevJoypadKeycodePressEmulated != 0)
356                                                 {
357                                                         // report key up event
358                                                         joypad_checked  = 1;
359                                                         new_state[_H6300_JOYPAD_REPORT_COLUMN]  = 32;   //100000
360                                                         report_key      = prevJoypadKeycodePressEmulated;
361                                                         report_col      = _H6300_JOYPAD_REPORT_COLUMN;
362                                                         switch(prevJoypadKeycodePressEmulated)
363                                                         {
364                                                                 case KEY_RIGHT:
365                                                                         report_row      = 0;
366                                                                         break;
367                                                                 case KEY_DOWN:
368                                                                         report_row      = 1;
369                                                                         break;
370                                                                 case KEY_LEFT:
371                                                                         report_row      = 2;
372                                                                         break;
373                                                                 case KEY_UP:
374                                                                         report_row      = 3;
375                                                                         break;
376                                                                 case KEY_ENTER:
377                                                                         report_row      = 4;
378                                                                         break;
379                                                                 default:
380                                                                         printk(KERN_WARNING "Unknown iPAQ h6300 column 1 key = %d released. This should newer happen!\n",
381                                                                                 key);
382                                                                         report_row      = 0;
383                                                         }
384                                                         input_report_key(omap_kp_data->input,
385                                                                         report_key,
386                                                                         new_state[report_col] & (1 << report_row));
387                                                         prevJoypadKeycodePressEmulated  = 0;
388                                                 }
389                                         }
390                                 }
391                         }
392                         else
393                         {
394                                 if (!(kp_cur_group == (key & GROUP_MASK) ||
395                                       kp_cur_group == -1))
396                                         continue;
397
398                                 kp_cur_group = key & GROUP_MASK;
399                                 input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
400                                                  !!(new_state[col] & (1 << row)));
401                         }
402 #endif
403                 }
404         }
405         memcpy(keypad_state, new_state, sizeof(keypad_state));
406
407         if (key_down) {
408                 int delay = HZ / 20;
409                 /* some key is pressed - keep irq disabled and use timer
410                  * to poll the keypad */
411                 if (spurious)
412                         delay = 2 * HZ;
413                 mod_timer(&omap_kp_data->timer, jiffies + delay);
414         } else {
415                 /* enable interrupts */
416                 if (cpu_is_omap24xx()) {
417                         int i;
418                         for (i = 0; i < omap_kp_data->rows; i++)
419                                 enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
420                 } else {
421                         omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
422                         kp_cur_group = -1;
423                 }
424         }
425 }
426
427 static ssize_t omap_kp_enable_show(struct device *dev, 
428                                    struct device_attribute *attr, char *buf)
429 {
430         return sprintf(buf, "%u\n", kp_enable);
431 }
432
433 static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
434                                     const char *buf, size_t count)
435 {
436         int state;
437
438         if (sscanf(buf, "%u", &state) != 1)
439                 return -EINVAL;
440
441         if ((state != 1) && (state != 0))
442                 return -EINVAL;
443
444         mutex_lock(&kp_enable_mutex);
445         if (state != kp_enable) {
446                 if (state)
447                         enable_irq(INT_KEYBOARD);
448                 else
449                         disable_irq(INT_KEYBOARD);
450                 kp_enable = state;
451         }
452         mutex_unlock(&kp_enable_mutex);
453
454         return strnlen(buf, count);
455 }
456
457 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
458
459 #ifdef CONFIG_PM
460 static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
461 {
462         /* Nothing yet */
463
464         return 0;
465 }
466
467 static int omap_kp_resume(struct platform_device *dev)
468 {
469         /* Nothing yet */
470
471         return 0;
472 }
473 #else
474 #define omap_kp_suspend NULL
475 #define omap_kp_resume  NULL
476 #endif
477
478 static int __init omap_kp_probe(struct platform_device *pdev)
479 {
480         struct omap_kp *omap_kp;
481         struct input_dev *input_dev;
482         struct omap_kp_platform_data *pdata =  pdev->dev.platform_data;
483         int i;
484
485         if (!pdata->rows || !pdata->cols || !pdata->keymap) {
486                 printk(KERN_ERR "No rows, cols or keymap from pdata\n");
487                 return -EINVAL;
488         }
489
490         omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
491         input_dev = input_allocate_device();
492         if (!omap_kp || !input_dev) {
493                 kfree(omap_kp);
494                 input_free_device(input_dev);
495                 return -ENOMEM;
496         }
497
498         platform_set_drvdata(pdev, omap_kp);
499
500         omap_kp->input = input_dev;
501
502         /* Disable the interrupt for the MPUIO keyboard */
503         if (!cpu_is_omap24xx())
504                 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
505
506         keymap = pdata->keymap;
507
508         if (pdata->rep)
509                 set_bit(EV_REP, input_dev->evbit);
510
511         if (pdata->row_gpios && pdata->col_gpios) {
512                 row_gpios = pdata->row_gpios;
513                 col_gpios = pdata->col_gpios;
514         }
515
516         omap_kp->rows = pdata->rows;
517         omap_kp->cols = pdata->cols;
518
519         if (cpu_is_omap24xx()) {
520                 /* Cols: outputs */
521                 for (i = 0; i < omap_kp->cols; i++) {
522                         if (omap_request_gpio(col_gpios[i]) < 0) {
523                                 printk(KERN_ERR "Failed to request"
524                                        "GPIO%d for keypad\n",
525                                        col_gpios[i]);
526                                 return -EINVAL;
527                         }
528                         omap_set_gpio_direction(col_gpios[i], 0);
529                 }
530                 /* Rows: inputs */
531                 for (i = 0; i < omap_kp->rows; i++) {
532                         if (omap_request_gpio(row_gpios[i]) < 0) {
533                                 printk(KERN_ERR "Failed to request"
534                                        "GPIO%d for keypad\n",
535                                        row_gpios[i]);
536                                 return -EINVAL;
537                         }
538                         omap_set_gpio_direction(row_gpios[i], 1);
539                 }
540         }
541         prevJoypadKeycodePressEmulated          = 0;
542
543         init_timer(&omap_kp->timer);
544         omap_kp->timer.function = omap_kp_timer;
545         omap_kp->timer.data = (unsigned long)omap_kp;
546
547         /* get the irq and init timer*/
548         tasklet_enable(&kp_tasklet);
549         kp_tasklet.data = (unsigned long) omap_kp;
550
551         omap_kp->irq = platform_get_irq(pdev, 0);
552         if (omap_kp->irq >= 0) {
553                 if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
554                                 "omap-keypad", omap_kp) < 0)
555                         return -EINVAL;
556         }
557
558         device_create_file(&pdev->dev, &dev_attr_enable);
559
560         /* setup input device */
561         set_bit(EV_KEY, input_dev->evbit);
562         for (i = 0; keymap[i] != 0; i++)
563                 set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
564         input_dev->name = "omap-keypad";
565         input_dev->cdev.dev = &pdev->dev;
566         input_dev->private = omap_kp;
567         input_register_device(omap_kp->input);
568
569         if (machine_is_omap_h2() || machine_is_omap_h3() ||
570             machine_is_omap_perseus2() || machine_is_omap_h6300()) {
571                 omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
572         }
573         /* scan current status and enable interrupt */
574         omap_kp_scan_keypad(omap_kp, keypad_state);
575         if (!cpu_is_omap24xx()) {
576                 omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
577         } else {
578                 for (i = 0; i < omap_kp->rows; i++) {
579                         if (request_irq(OMAP_GPIO_IRQ(row_gpios[i]), omap_kp_interrupt,
580                                         SA_TRIGGER_FALLING, "omap-keypad", omap_kp) < 0)
581                                 return -EINVAL;
582                 }
583         }
584
585         return 0;
586 }
587
588 static int omap_kp_remove(struct platform_device *pdev)
589 {
590         struct omap_kp *omap_kp = platform_get_drvdata(pdev);
591
592         /* disable keypad interrupt handling */
593         tasklet_disable(&kp_tasklet);
594         if (cpu_is_omap24xx()) {
595                 int i;
596                 for (i = 0; i < omap_kp->cols; i++)
597                         omap_free_gpio(col_gpios[i]);
598                 for (i = 0; i < omap_kp->rows; i++) {
599                         omap_free_gpio(row_gpios[i]);
600                         free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
601                 }
602         } else {
603                 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
604                 free_irq(omap_kp->irq, 0);
605         }
606
607         del_timer_sync(&omap_kp->timer);
608
609         /* unregister everything */
610         input_unregister_device(omap_kp->input);
611
612         kfree(omap_kp);
613
614         return 0;
615 }
616
617 static struct platform_driver omap_kp_driver = {
618         .probe          = omap_kp_probe,
619         .remove         = omap_kp_remove,
620         .suspend        = omap_kp_suspend,
621         .resume         = omap_kp_resume,
622         .driver         = {
623                 .name   = "omap-keypad",
624         },
625 };
626
627 static int __devinit omap_kp_init(void)
628 {
629         printk(KERN_INFO "OMAP Keypad Driver\n");
630         return platform_driver_register(&omap_kp_driver);
631 }
632
633 static void __exit omap_kp_exit(void)
634 {
635         platform_driver_unregister(&omap_kp_driver);
636 }
637
638 module_init(omap_kp_init);
639 module_exit(omap_kp_exit);
640
641 MODULE_AUTHOR("Timo Teräs");
642 MODULE_DESCRIPTION("OMAP Keypad Driver");
643 MODULE_LICENSE("GPL");