aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorAlberto Panizzo <maramaopercheseimorto@gmail.com>2010-01-31 20:52:07 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-31 20:52:57 -0500
commit76cdc083f4d1a2a12a961634672fb9ca7adca29c (patch)
treef23789194c929fa1d33c376e24478d7f0f255bb8 /drivers/input
parent429722e19dff319aa87ee552beadee71d41a3655 (diff)
Input: add imx-keypad driver to support the IMX Keypad Port
The IMX family of Application Processors is shipped with a Keypad Port supported by this driver. The peripheral can control up to an 8x8 matrix key pad where all the scanning is done via software. The hardware provides two interrupts: one for key presses (KDI) and one for all key releases (KRI). There is also a simple circuit for glitch reduction (said for synchronization) made by two series of 3 D-latches clocked by the keypad-clock that stabilize the interrupts sources. KDI and KRI are fired only if the respective conditions are maintained for at last 4 keypad-clock cycle. Since those circuits are poor for a correct debounce process (the keypad-clock frequency is 32K and bounces longer than 94us are not masked) the driver, when an interrupt arrives, samples the matrix with a period of 10ms until the readins are stable for IMX_KEYPAD_SCANS_FOR_STABILITY times (currently set at 3). After getting stable result appropriate events are sent through the input stack. If some keys are maintained pressed, the driver continues to scan the matrix with a longer period (60ms) to catch possible multiple key presses without overloading the cpu. This process ends when all keys are released. This driver is tested to build in kernel or as a module and follow the specification of Freescale Application processors: i.MX25 i.MX27 i.MX31 i.MX35 i.MX51 especially tested on i.MX31. Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-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 c72283c6916..616a3916d18 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 78654ef6520..706c6b5ed5f 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 00000000000..2ee5b798024
--- /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");