2 * Samsung keypad driver
4 * Copyright (C) 2010 Samsung Electronics Co.Ltd
5 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6 * Author: Donghwa Lee <dh09.lee@samsung.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/clk.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/init.h>
18 #include <linux/input.h>
19 #include <linux/interrupt.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/sched.h>
25 #include <plat/keypad.h>
27 #define SAMSUNG_KEYIFCON 0x00
28 #define SAMSUNG_KEYIFSTSCLR 0x04
29 #define SAMSUNG_KEYIFCOL 0x08
30 #define SAMSUNG_KEYIFROW 0x0c
31 #define SAMSUNG_KEYIFFC 0x10
33 /* SAMSUNG_KEYIFCON */
34 #define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
35 #define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
36 #define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
37 #define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
38 #define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
40 /* SAMSUNG_KEYIFSTSCLR */
41 #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
42 #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8)
43 #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8
44 #define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0)
45 #define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16)
46 #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
48 /* SAMSUNG_KEYIFCOL */
49 #define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
50 #define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
52 /* SAMSUNG_KEYIFROW */
53 #define SAMSUNG_KEYIFROW_MASK (0xff << 0)
54 #define S5PV210_KEYIFROW_MASK (0x3fff << 0)
57 #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
59 enum samsung_keypad_type
{
64 struct samsung_keypad
{
65 struct input_dev
*input_dev
;
68 wait_queue_head_t wait
;
71 unsigned int row_shift
;
74 unsigned int row_state
[SAMSUNG_MAX_COLS
];
75 unsigned short keycodes
[];
78 static int samsung_keypad_is_s5pv210(struct device
*dev
)
80 struct platform_device
*pdev
= to_platform_device(dev
);
81 enum samsung_keypad_type type
=
82 platform_get_device_id(pdev
)->driver_data
;
84 return type
== KEYPAD_TYPE_S5PV210
;
87 static void samsung_keypad_scan(struct samsung_keypad
*keypad
,
88 unsigned int *row_state
)
90 struct device
*dev
= keypad
->input_dev
->dev
.parent
;
94 for (col
= 0; col
< keypad
->cols
; col
++) {
95 if (samsung_keypad_is_s5pv210(dev
)) {
96 val
= S5PV210_KEYIFCOLEN_MASK
;
97 val
&= ~(1 << col
) << 8;
99 val
= SAMSUNG_KEYIFCOL_MASK
;
103 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCOL
);
106 val
= readl(keypad
->base
+ SAMSUNG_KEYIFROW
);
107 row_state
[col
] = ~val
& ((1 << keypad
->rows
) - 1);
110 /* KEYIFCOL reg clear */
111 writel(0, keypad
->base
+ SAMSUNG_KEYIFCOL
);
114 static bool samsung_keypad_report(struct samsung_keypad
*keypad
,
115 unsigned int *row_state
)
117 struct input_dev
*input_dev
= keypad
->input_dev
;
118 unsigned int changed
;
119 unsigned int pressed
;
120 unsigned int key_down
= 0;
122 unsigned int col
, row
;
124 for (col
= 0; col
< keypad
->cols
; col
++) {
125 changed
= row_state
[col
] ^ keypad
->row_state
[col
];
126 key_down
|= row_state
[col
];
130 for (row
= 0; row
< keypad
->rows
; row
++) {
131 if (!(changed
& (1 << row
)))
134 pressed
= row_state
[col
] & (1 << row
);
136 dev_dbg(&keypad
->input_dev
->dev
,
137 "key %s, row: %d, col: %d\n",
138 pressed
? "pressed" : "released", row
, col
);
140 val
= MATRIX_SCAN_CODE(row
, col
, keypad
->row_shift
);
142 input_event(input_dev
, EV_MSC
, MSC_SCAN
, val
);
143 input_report_key(input_dev
,
144 keypad
->keycodes
[val
], pressed
);
146 input_sync(keypad
->input_dev
);
149 memcpy(keypad
->row_state
, row_state
, sizeof(keypad
->row_state
));
154 static irqreturn_t
samsung_keypad_irq(int irq
, void *dev_id
)
156 struct samsung_keypad
*keypad
= dev_id
;
157 unsigned int row_state
[SAMSUNG_MAX_COLS
];
162 val
= readl(keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
163 /* Clear interrupt. */
164 writel(~0x0, keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
166 samsung_keypad_scan(keypad
, row_state
);
168 key_down
= samsung_keypad_report(keypad
, row_state
);
170 wait_event_timeout(keypad
->wait
, keypad
->stopped
,
171 msecs_to_jiffies(50));
173 } while (key_down
&& !keypad
->stopped
);
178 static void samsung_keypad_start(struct samsung_keypad
*keypad
)
182 /* Tell IRQ thread that it may poll the device. */
183 keypad
->stopped
= false;
185 clk_enable(keypad
->clk
);
187 /* Enable interrupt bits. */
188 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
189 val
|= SAMSUNG_KEYIFCON_INT_F_EN
| SAMSUNG_KEYIFCON_INT_R_EN
;
190 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
192 /* KEYIFCOL reg clear. */
193 writel(0, keypad
->base
+ SAMSUNG_KEYIFCOL
);
196 static void samsung_keypad_stop(struct samsung_keypad
*keypad
)
200 /* Signal IRQ thread to stop polling and disable the handler. */
201 keypad
->stopped
= true;
202 wake_up(&keypad
->wait
);
203 disable_irq(keypad
->irq
);
205 /* Clear interrupt. */
206 writel(~0x0, keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
208 /* Disable interrupt bits. */
209 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
210 val
&= ~(SAMSUNG_KEYIFCON_INT_F_EN
| SAMSUNG_KEYIFCON_INT_R_EN
);
211 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
213 clk_disable(keypad
->clk
);
216 * Now that chip should not generate interrupts we can safely
217 * re-enable the handler.
219 enable_irq(keypad
->irq
);
222 static int samsung_keypad_open(struct input_dev
*input_dev
)
224 struct samsung_keypad
*keypad
= input_get_drvdata(input_dev
);
226 samsung_keypad_start(keypad
);
231 static void samsung_keypad_close(struct input_dev
*input_dev
)
233 struct samsung_keypad
*keypad
= input_get_drvdata(input_dev
);
235 samsung_keypad_stop(keypad
);
238 static int __devinit
samsung_keypad_probe(struct platform_device
*pdev
)
240 const struct samsung_keypad_platdata
*pdata
;
241 const struct matrix_keymap_data
*keymap_data
;
242 struct samsung_keypad
*keypad
;
243 struct resource
*res
;
244 struct input_dev
*input_dev
;
245 unsigned int row_shift
;
246 unsigned int keymap_size
;
249 pdata
= pdev
->dev
.platform_data
;
251 dev_err(&pdev
->dev
, "no platform data defined\n");
255 keymap_data
= pdata
->keymap_data
;
257 dev_err(&pdev
->dev
, "no keymap data defined\n");
261 if (!pdata
->rows
|| pdata
->rows
> SAMSUNG_MAX_ROWS
)
264 if (!pdata
->cols
|| pdata
->cols
> SAMSUNG_MAX_COLS
)
267 /* initialize the gpio */
269 pdata
->cfg_gpio(pdata
->rows
, pdata
->cols
);
271 row_shift
= get_count_order(pdata
->cols
);
272 keymap_size
= (pdata
->rows
<< row_shift
) * sizeof(keypad
->keycodes
[0]);
274 keypad
= kzalloc(sizeof(*keypad
) + keymap_size
, GFP_KERNEL
);
275 input_dev
= input_allocate_device();
276 if (!keypad
|| !input_dev
) {
281 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
287 keypad
->base
= ioremap(res
->start
, resource_size(res
));
293 keypad
->clk
= clk_get(&pdev
->dev
, "keypad");
294 if (IS_ERR(keypad
->clk
)) {
295 dev_err(&pdev
->dev
, "failed to get keypad clk\n");
296 error
= PTR_ERR(keypad
->clk
);
300 keypad
->input_dev
= input_dev
;
301 keypad
->row_shift
= row_shift
;
302 keypad
->rows
= pdata
->rows
;
303 keypad
->cols
= pdata
->cols
;
304 init_waitqueue_head(&keypad
->wait
);
306 input_dev
->name
= pdev
->name
;
307 input_dev
->id
.bustype
= BUS_HOST
;
308 input_dev
->dev
.parent
= &pdev
->dev
;
309 input_set_drvdata(input_dev
, keypad
);
311 input_dev
->open
= samsung_keypad_open
;
312 input_dev
->close
= samsung_keypad_close
;
314 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
);
315 if (!pdata
->no_autorepeat
)
316 input_dev
->evbit
[0] |= BIT_MASK(EV_REP
);
318 input_set_capability(input_dev
, EV_MSC
, MSC_SCAN
);
320 input_dev
->keycode
= keypad
->keycodes
;
321 input_dev
->keycodesize
= sizeof(keypad
->keycodes
[0]);
322 input_dev
->keycodemax
= pdata
->rows
<< row_shift
;
324 matrix_keypad_build_keymap(keymap_data
, row_shift
,
325 input_dev
->keycode
, input_dev
->keybit
);
327 keypad
->irq
= platform_get_irq(pdev
, 0);
328 if (keypad
->irq
< 0) {
333 error
= request_threaded_irq(keypad
->irq
, NULL
, samsung_keypad_irq
,
334 IRQF_ONESHOT
, dev_name(&pdev
->dev
), keypad
);
336 dev_err(&pdev
->dev
, "failed to register keypad interrupt\n");
340 error
= input_register_device(keypad
->input_dev
);
344 device_init_wakeup(&pdev
->dev
, pdata
->wakeup
);
345 platform_set_drvdata(pdev
, keypad
);
349 free_irq(keypad
->irq
, keypad
);
351 clk_put(keypad
->clk
);
353 iounmap(keypad
->base
);
355 input_free_device(input_dev
);
361 static int __devexit
samsung_keypad_remove(struct platform_device
*pdev
)
363 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
365 device_init_wakeup(&pdev
->dev
, 0);
366 platform_set_drvdata(pdev
, NULL
);
368 input_unregister_device(keypad
->input_dev
);
371 * It is safe to free IRQ after unregistering device because
372 * samsung_keypad_close will shut off interrupts.
374 free_irq(keypad
->irq
, keypad
);
376 clk_put(keypad
->clk
);
378 iounmap(keypad
->base
);
385 static void samsung_keypad_toggle_wakeup(struct samsung_keypad
*keypad
,
388 struct device
*dev
= keypad
->input_dev
->dev
.parent
;
391 clk_enable(keypad
->clk
);
393 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
395 val
|= SAMSUNG_KEYIFCON_WAKEUPEN
;
396 if (device_may_wakeup(dev
))
397 enable_irq_wake(keypad
->irq
);
399 val
&= ~SAMSUNG_KEYIFCON_WAKEUPEN
;
400 if (device_may_wakeup(dev
))
401 disable_irq_wake(keypad
->irq
);
403 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
405 clk_disable(keypad
->clk
);
408 static int samsung_keypad_suspend(struct device
*dev
)
410 struct platform_device
*pdev
= to_platform_device(dev
);
411 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
412 struct input_dev
*input_dev
= keypad
->input_dev
;
414 mutex_lock(&input_dev
->mutex
);
416 if (input_dev
->users
)
417 samsung_keypad_stop(keypad
);
419 samsung_keypad_toggle_wakeup(keypad
, true);
421 mutex_unlock(&input_dev
->mutex
);
426 static int samsung_keypad_resume(struct device
*dev
)
428 struct platform_device
*pdev
= to_platform_device(dev
);
429 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
430 struct input_dev
*input_dev
= keypad
->input_dev
;
432 mutex_lock(&input_dev
->mutex
);
434 samsung_keypad_toggle_wakeup(keypad
, false);
436 if (input_dev
->users
)
437 samsung_keypad_start(keypad
);
439 mutex_unlock(&input_dev
->mutex
);
444 static const struct dev_pm_ops samsung_keypad_pm_ops
= {
445 .suspend
= samsung_keypad_suspend
,
446 .resume
= samsung_keypad_resume
,
450 static struct platform_device_id samsung_keypad_driver_ids
[] = {
452 .name
= "samsung-keypad",
453 .driver_data
= KEYPAD_TYPE_SAMSUNG
,
455 .name
= "s5pv210-keypad",
456 .driver_data
= KEYPAD_TYPE_S5PV210
,
460 MODULE_DEVICE_TABLE(platform
, samsung_keypad_driver_ids
);
462 static struct platform_driver samsung_keypad_driver
= {
463 .probe
= samsung_keypad_probe
,
464 .remove
= __devexit_p(samsung_keypad_remove
),
466 .name
= "samsung-keypad",
467 .owner
= THIS_MODULE
,
469 .pm
= &samsung_keypad_pm_ops
,
472 .id_table
= samsung_keypad_driver_ids
,
475 static int __init
samsung_keypad_init(void)
477 return platform_driver_register(&samsung_keypad_driver
);
479 module_init(samsung_keypad_init
);
481 static void __exit
samsung_keypad_exit(void)
483 platform_driver_unregister(&samsung_keypad_driver
);
485 module_exit(samsung_keypad_exit
);
487 MODULE_DESCRIPTION("Samsung keypad driver");
488 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
489 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
490 MODULE_LICENSE("GPL");
491 MODULE_ALIAS("platform:samsung-keypad");