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/input.h>
18 #include <linux/interrupt.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/slab.h>
26 #include <linux/sched.h>
27 #include <linux/input/samsung-keypad.h>
29 #define SAMSUNG_KEYIFCON 0x00
30 #define SAMSUNG_KEYIFSTSCLR 0x04
31 #define SAMSUNG_KEYIFCOL 0x08
32 #define SAMSUNG_KEYIFROW 0x0c
33 #define SAMSUNG_KEYIFFC 0x10
35 /* SAMSUNG_KEYIFCON */
36 #define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
37 #define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
38 #define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
39 #define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
40 #define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
42 /* SAMSUNG_KEYIFSTSCLR */
43 #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
44 #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8)
45 #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8
46 #define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0)
47 #define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16)
48 #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
50 /* SAMSUNG_KEYIFCOL */
51 #define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
52 #define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
54 /* SAMSUNG_KEYIFROW */
55 #define SAMSUNG_KEYIFROW_MASK (0xff << 0)
56 #define S5PV210_KEYIFROW_MASK (0x3fff << 0)
59 #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
61 enum samsung_keypad_type
{
66 struct samsung_keypad
{
67 struct input_dev
*input_dev
;
68 struct platform_device
*pdev
;
71 wait_queue_head_t wait
;
75 enum samsung_keypad_type type
;
76 unsigned int row_shift
;
79 unsigned int row_state
[SAMSUNG_MAX_COLS
];
80 unsigned short keycodes
[];
83 static void samsung_keypad_scan(struct samsung_keypad
*keypad
,
84 unsigned int *row_state
)
89 for (col
= 0; col
< keypad
->cols
; col
++) {
90 if (keypad
->type
== KEYPAD_TYPE_S5PV210
) {
91 val
= S5PV210_KEYIFCOLEN_MASK
;
92 val
&= ~(1 << col
) << 8;
94 val
= SAMSUNG_KEYIFCOL_MASK
;
98 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCOL
);
101 val
= readl(keypad
->base
+ SAMSUNG_KEYIFROW
);
102 row_state
[col
] = ~val
& ((1 << keypad
->rows
) - 1);
105 /* KEYIFCOL reg clear */
106 writel(0, keypad
->base
+ SAMSUNG_KEYIFCOL
);
109 static bool samsung_keypad_report(struct samsung_keypad
*keypad
,
110 unsigned int *row_state
)
112 struct input_dev
*input_dev
= keypad
->input_dev
;
113 unsigned int changed
;
114 unsigned int pressed
;
115 unsigned int key_down
= 0;
117 unsigned int col
, row
;
119 for (col
= 0; col
< keypad
->cols
; col
++) {
120 changed
= row_state
[col
] ^ keypad
->row_state
[col
];
121 key_down
|= row_state
[col
];
125 for (row
= 0; row
< keypad
->rows
; row
++) {
126 if (!(changed
& (1 << row
)))
129 pressed
= row_state
[col
] & (1 << row
);
131 dev_dbg(&keypad
->input_dev
->dev
,
132 "key %s, row: %d, col: %d\n",
133 pressed
? "pressed" : "released", row
, col
);
135 val
= MATRIX_SCAN_CODE(row
, col
, keypad
->row_shift
);
137 input_event(input_dev
, EV_MSC
, MSC_SCAN
, val
);
138 input_report_key(input_dev
,
139 keypad
->keycodes
[val
], pressed
);
141 input_sync(keypad
->input_dev
);
144 memcpy(keypad
->row_state
, row_state
, sizeof(keypad
->row_state
));
149 static irqreturn_t
samsung_keypad_irq(int irq
, void *dev_id
)
151 struct samsung_keypad
*keypad
= dev_id
;
152 unsigned int row_state
[SAMSUNG_MAX_COLS
];
156 pm_runtime_get_sync(&keypad
->pdev
->dev
);
159 val
= readl(keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
160 /* Clear interrupt. */
161 writel(~0x0, keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
163 samsung_keypad_scan(keypad
, row_state
);
165 key_down
= samsung_keypad_report(keypad
, row_state
);
167 wait_event_timeout(keypad
->wait
, keypad
->stopped
,
168 msecs_to_jiffies(50));
170 } while (key_down
&& !keypad
->stopped
);
172 pm_runtime_put(&keypad
->pdev
->dev
);
177 static void samsung_keypad_start(struct samsung_keypad
*keypad
)
181 pm_runtime_get_sync(&keypad
->pdev
->dev
);
183 /* Tell IRQ thread that it may poll the device. */
184 keypad
->stopped
= false;
186 clk_enable(keypad
->clk
);
188 /* Enable interrupt bits. */
189 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
190 val
|= SAMSUNG_KEYIFCON_INT_F_EN
| SAMSUNG_KEYIFCON_INT_R_EN
;
191 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
193 /* KEYIFCOL reg clear. */
194 writel(0, keypad
->base
+ SAMSUNG_KEYIFCOL
);
196 pm_runtime_put(&keypad
->pdev
->dev
);
199 static void samsung_keypad_stop(struct samsung_keypad
*keypad
)
203 pm_runtime_get_sync(&keypad
->pdev
->dev
);
205 /* Signal IRQ thread to stop polling and disable the handler. */
206 keypad
->stopped
= true;
207 wake_up(&keypad
->wait
);
208 disable_irq(keypad
->irq
);
210 /* Clear interrupt. */
211 writel(~0x0, keypad
->base
+ SAMSUNG_KEYIFSTSCLR
);
213 /* Disable interrupt bits. */
214 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
215 val
&= ~(SAMSUNG_KEYIFCON_INT_F_EN
| SAMSUNG_KEYIFCON_INT_R_EN
);
216 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
218 clk_disable(keypad
->clk
);
221 * Now that chip should not generate interrupts we can safely
222 * re-enable the handler.
224 enable_irq(keypad
->irq
);
226 pm_runtime_put(&keypad
->pdev
->dev
);
229 static int samsung_keypad_open(struct input_dev
*input_dev
)
231 struct samsung_keypad
*keypad
= input_get_drvdata(input_dev
);
233 samsung_keypad_start(keypad
);
238 static void samsung_keypad_close(struct input_dev
*input_dev
)
240 struct samsung_keypad
*keypad
= input_get_drvdata(input_dev
);
242 samsung_keypad_stop(keypad
);
246 static struct samsung_keypad_platdata
*
247 samsung_keypad_parse_dt(struct device
*dev
)
249 struct samsung_keypad_platdata
*pdata
;
250 struct matrix_keymap_data
*keymap_data
;
251 uint32_t *keymap
, num_rows
= 0, num_cols
= 0;
252 struct device_node
*np
= dev
->of_node
, *key_np
;
253 unsigned int key_count
;
256 dev_err(dev
, "missing device tree data\n");
257 return ERR_PTR(-EINVAL
);
260 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
262 dev_err(dev
, "could not allocate memory for platform data\n");
263 return ERR_PTR(-ENOMEM
);
266 of_property_read_u32(np
, "samsung,keypad-num-rows", &num_rows
);
267 of_property_read_u32(np
, "samsung,keypad-num-columns", &num_cols
);
268 if (!num_rows
|| !num_cols
) {
269 dev_err(dev
, "number of keypad rows/columns not specified\n");
270 return ERR_PTR(-EINVAL
);
272 pdata
->rows
= num_rows
;
273 pdata
->cols
= num_cols
;
275 keymap_data
= devm_kzalloc(dev
, sizeof(*keymap_data
), GFP_KERNEL
);
277 dev_err(dev
, "could not allocate memory for keymap data\n");
278 return ERR_PTR(-ENOMEM
);
280 pdata
->keymap_data
= keymap_data
;
282 key_count
= of_get_child_count(np
);
283 keymap_data
->keymap_size
= key_count
;
284 keymap
= devm_kzalloc(dev
, sizeof(uint32_t) * key_count
, GFP_KERNEL
);
286 dev_err(dev
, "could not allocate memory for keymap\n");
287 return ERR_PTR(-ENOMEM
);
289 keymap_data
->keymap
= keymap
;
291 for_each_child_of_node(np
, key_np
) {
292 u32 row
, col
, key_code
;
293 of_property_read_u32(key_np
, "keypad,row", &row
);
294 of_property_read_u32(key_np
, "keypad,column", &col
);
295 of_property_read_u32(key_np
, "linux,code", &key_code
);
296 *keymap
++ = KEY(row
, col
, key_code
);
299 if (of_get_property(np
, "linux,input-no-autorepeat", NULL
))
300 pdata
->no_autorepeat
= true;
302 pdata
->wakeup
= of_property_read_bool(np
, "wakeup-source") ||
304 of_property_read_bool(np
, "linux,input-wakeup");
310 static struct samsung_keypad_platdata
*
311 samsung_keypad_parse_dt(struct device
*dev
)
313 dev_err(dev
, "no platform data defined\n");
315 return ERR_PTR(-EINVAL
);
319 static int samsung_keypad_probe(struct platform_device
*pdev
)
321 const struct samsung_keypad_platdata
*pdata
;
322 const struct matrix_keymap_data
*keymap_data
;
323 struct samsung_keypad
*keypad
;
324 struct resource
*res
;
325 struct input_dev
*input_dev
;
326 unsigned int row_shift
;
327 unsigned int keymap_size
;
330 pdata
= dev_get_platdata(&pdev
->dev
);
332 pdata
= samsung_keypad_parse_dt(&pdev
->dev
);
334 return PTR_ERR(pdata
);
337 keymap_data
= pdata
->keymap_data
;
339 dev_err(&pdev
->dev
, "no keymap data defined\n");
343 if (!pdata
->rows
|| pdata
->rows
> SAMSUNG_MAX_ROWS
)
346 if (!pdata
->cols
|| pdata
->cols
> SAMSUNG_MAX_COLS
)
349 /* initialize the gpio */
351 pdata
->cfg_gpio(pdata
->rows
, pdata
->cols
);
353 row_shift
= get_count_order(pdata
->cols
);
354 keymap_size
= (pdata
->rows
<< row_shift
) * sizeof(keypad
->keycodes
[0]);
356 keypad
= devm_kzalloc(&pdev
->dev
, sizeof(*keypad
) + keymap_size
,
358 input_dev
= devm_input_allocate_device(&pdev
->dev
);
359 if (!keypad
|| !input_dev
)
362 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
366 keypad
->base
= devm_ioremap(&pdev
->dev
, res
->start
, resource_size(res
));
370 keypad
->clk
= devm_clk_get(&pdev
->dev
, "keypad");
371 if (IS_ERR(keypad
->clk
)) {
372 dev_err(&pdev
->dev
, "failed to get keypad clk\n");
373 return PTR_ERR(keypad
->clk
);
376 error
= clk_prepare(keypad
->clk
);
378 dev_err(&pdev
->dev
, "keypad clock prepare failed\n");
382 keypad
->input_dev
= input_dev
;
384 keypad
->row_shift
= row_shift
;
385 keypad
->rows
= pdata
->rows
;
386 keypad
->cols
= pdata
->cols
;
387 keypad
->stopped
= true;
388 init_waitqueue_head(&keypad
->wait
);
390 if (pdev
->dev
.of_node
)
391 keypad
->type
= of_device_is_compatible(pdev
->dev
.of_node
,
392 "samsung,s5pv210-keypad");
394 keypad
->type
= platform_get_device_id(pdev
)->driver_data
;
396 input_dev
->name
= pdev
->name
;
397 input_dev
->id
.bustype
= BUS_HOST
;
398 input_dev
->dev
.parent
= &pdev
->dev
;
400 input_dev
->open
= samsung_keypad_open
;
401 input_dev
->close
= samsung_keypad_close
;
403 error
= matrix_keypad_build_keymap(keymap_data
, NULL
,
404 pdata
->rows
, pdata
->cols
,
405 keypad
->keycodes
, input_dev
);
407 dev_err(&pdev
->dev
, "failed to build keymap\n");
408 goto err_unprepare_clk
;
411 input_set_capability(input_dev
, EV_MSC
, MSC_SCAN
);
412 if (!pdata
->no_autorepeat
)
413 __set_bit(EV_REP
, input_dev
->evbit
);
415 input_set_drvdata(input_dev
, keypad
);
417 keypad
->irq
= platform_get_irq(pdev
, 0);
418 if (keypad
->irq
< 0) {
420 goto err_unprepare_clk
;
423 error
= devm_request_threaded_irq(&pdev
->dev
, keypad
->irq
, NULL
,
424 samsung_keypad_irq
, IRQF_ONESHOT
,
425 dev_name(&pdev
->dev
), keypad
);
427 dev_err(&pdev
->dev
, "failed to register keypad interrupt\n");
428 goto err_unprepare_clk
;
431 device_init_wakeup(&pdev
->dev
, pdata
->wakeup
);
432 platform_set_drvdata(pdev
, keypad
);
433 pm_runtime_enable(&pdev
->dev
);
435 error
= input_register_device(keypad
->input_dev
);
437 goto err_disable_runtime_pm
;
439 if (pdev
->dev
.of_node
) {
440 devm_kfree(&pdev
->dev
, (void *)pdata
->keymap_data
->keymap
);
441 devm_kfree(&pdev
->dev
, (void *)pdata
->keymap_data
);
442 devm_kfree(&pdev
->dev
, (void *)pdata
);
446 err_disable_runtime_pm
:
447 pm_runtime_disable(&pdev
->dev
);
448 device_init_wakeup(&pdev
->dev
, 0);
450 clk_unprepare(keypad
->clk
);
454 static int samsung_keypad_remove(struct platform_device
*pdev
)
456 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
458 pm_runtime_disable(&pdev
->dev
);
459 device_init_wakeup(&pdev
->dev
, 0);
461 input_unregister_device(keypad
->input_dev
);
463 clk_unprepare(keypad
->clk
);
469 static int samsung_keypad_runtime_suspend(struct device
*dev
)
471 struct platform_device
*pdev
= to_platform_device(dev
);
472 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
479 /* This may fail on some SoCs due to lack of controller support */
480 error
= enable_irq_wake(keypad
->irq
);
482 keypad
->wake_enabled
= true;
484 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
485 val
|= SAMSUNG_KEYIFCON_WAKEUPEN
;
486 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
488 clk_disable(keypad
->clk
);
493 static int samsung_keypad_runtime_resume(struct device
*dev
)
495 struct platform_device
*pdev
= to_platform_device(dev
);
496 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
502 clk_enable(keypad
->clk
);
504 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
505 val
&= ~SAMSUNG_KEYIFCON_WAKEUPEN
;
506 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
508 if (keypad
->wake_enabled
)
509 disable_irq_wake(keypad
->irq
);
515 #ifdef CONFIG_PM_SLEEP
516 static void samsung_keypad_toggle_wakeup(struct samsung_keypad
*keypad
,
521 clk_enable(keypad
->clk
);
523 val
= readl(keypad
->base
+ SAMSUNG_KEYIFCON
);
525 val
|= SAMSUNG_KEYIFCON_WAKEUPEN
;
526 if (device_may_wakeup(&keypad
->pdev
->dev
))
527 enable_irq_wake(keypad
->irq
);
529 val
&= ~SAMSUNG_KEYIFCON_WAKEUPEN
;
530 if (device_may_wakeup(&keypad
->pdev
->dev
))
531 disable_irq_wake(keypad
->irq
);
533 writel(val
, keypad
->base
+ SAMSUNG_KEYIFCON
);
535 clk_disable(keypad
->clk
);
538 static int samsung_keypad_suspend(struct device
*dev
)
540 struct platform_device
*pdev
= to_platform_device(dev
);
541 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
542 struct input_dev
*input_dev
= keypad
->input_dev
;
544 mutex_lock(&input_dev
->mutex
);
546 if (input_dev
->users
)
547 samsung_keypad_stop(keypad
);
549 samsung_keypad_toggle_wakeup(keypad
, true);
551 mutex_unlock(&input_dev
->mutex
);
556 static int samsung_keypad_resume(struct device
*dev
)
558 struct platform_device
*pdev
= to_platform_device(dev
);
559 struct samsung_keypad
*keypad
= platform_get_drvdata(pdev
);
560 struct input_dev
*input_dev
= keypad
->input_dev
;
562 mutex_lock(&input_dev
->mutex
);
564 samsung_keypad_toggle_wakeup(keypad
, false);
566 if (input_dev
->users
)
567 samsung_keypad_start(keypad
);
569 mutex_unlock(&input_dev
->mutex
);
575 static const struct dev_pm_ops samsung_keypad_pm_ops
= {
576 SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend
, samsung_keypad_resume
)
577 SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend
,
578 samsung_keypad_runtime_resume
, NULL
)
582 static const struct of_device_id samsung_keypad_dt_match
[] = {
583 { .compatible
= "samsung,s3c6410-keypad" },
584 { .compatible
= "samsung,s5pv210-keypad" },
587 MODULE_DEVICE_TABLE(of
, samsung_keypad_dt_match
);
590 static const struct platform_device_id samsung_keypad_driver_ids
[] = {
592 .name
= "samsung-keypad",
593 .driver_data
= KEYPAD_TYPE_SAMSUNG
,
595 .name
= "s5pv210-keypad",
596 .driver_data
= KEYPAD_TYPE_S5PV210
,
600 MODULE_DEVICE_TABLE(platform
, samsung_keypad_driver_ids
);
602 static struct platform_driver samsung_keypad_driver
= {
603 .probe
= samsung_keypad_probe
,
604 .remove
= samsung_keypad_remove
,
606 .name
= "samsung-keypad",
607 .of_match_table
= of_match_ptr(samsung_keypad_dt_match
),
608 .pm
= &samsung_keypad_pm_ops
,
610 .id_table
= samsung_keypad_driver_ids
,
612 module_platform_driver(samsung_keypad_driver
);
614 MODULE_DESCRIPTION("Samsung keypad driver");
615 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
616 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
617 MODULE_LICENSE("GPL");