aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2011-11-02 06:37:22 -0400
committerKukjin Kim <kgene.kim@samsung.com>2011-12-22 20:07:10 -0500
commitb3d6ac3e5f937440a362c0fa187257fa1197f5b9 (patch)
treef9d535987acc864a3948174e893077b5f6543138
parent8742e0441d6530d40d85d65a6bcc5a6c0c4eab13 (diff)
input: samsung-keypad: Add device tree support
Add device tree based discovery support for Samsung's keypad controller. Cc: Joonyoung Shim <jy0922.shim@samsung.com> Cc: Donghwa Lee <dh09.lee@samsung.com> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--Documentation/devicetree/bindings/input/samsung-keypad.txt88
-rw-r--r--drivers/input/keyboard/samsung-keypad.c174
2 files changed, 250 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt
new file mode 100644
index 000000000000..ce3e394c0e64
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt
@@ -0,0 +1,88 @@
1* Samsung's Keypad Controller device tree bindings
2
3Samsung's Keypad controller is used to interface a SoC with a matrix-type
4keypad device. The keypad controller supports multiple row and column lines.
5A key can be placed at each intersection of a unique row and a unique column.
6The keypad controller can sense a key-press and key-release and report the
7event using a interrupt to the cpu.
8
9Required SoC Specific Properties:
10- compatible: should be one of the following
11 - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad
12 controller.
13 - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad
14 controller.
15
16- reg: physical base address of the controller and length of memory mapped
17 region.
18
19- interrupts: The interrupt number to the cpu.
20
21Required Board Specific Properties:
22- samsung,keypad-num-rows: Number of row lines connected to the keypad
23 controller.
24
25- samsung,keypad-num-columns: Number of column lines connected to the
26 keypad controller.
27
28- row-gpios: List of gpios used as row lines. The gpio specifier for
29 this property depends on the gpio controller to which these row lines
30 are connected.
31
32- col-gpios: List of gpios used as column lines. The gpio specifier for
33 this property depends on the gpio controller to which these column
34 lines are connected.
35
36- Keys represented as child nodes: Each key connected to the keypad
37 controller is represented as a child node to the keypad controller
38 device node and should include the following properties.
39 - keypad,row: the row number to which the key is connected.
40 - keypad,column: the column number to which the key is connected.
41 - linux,code: the key-code to be reported when the key is pressed
42 and released.
43
44Optional Properties specific to linux:
45- linux,keypad-no-autorepeat: do no enable autorepeat feature.
46- linux,keypad-wakeup: use any event on keypad as wakeup event.
47
48
49Example:
50 keypad@100A0000 {
51 compatible = "samsung,s5pv210-keypad";
52 reg = <0x100A0000 0x100>;
53 interrupts = <173>;
54 samsung,keypad-num-rows = <2>;
55 samsung,keypad-num-columns = <8>;
56 linux,input-no-autorepeat;
57 linux,input-wakeup;
58
59 row-gpios = <&gpx2 0 3 3 0
60 &gpx2 1 3 3 0>;
61
62 col-gpios = <&gpx1 0 3 0 0
63 &gpx1 1 3 0 0
64 &gpx1 2 3 0 0
65 &gpx1 3 3 0 0
66 &gpx1 4 3 0 0
67 &gpx1 5 3 0 0
68 &gpx1 6 3 0 0
69 &gpx1 7 3 0 0>;
70
71 key_1 {
72 keypad,row = <0>;
73 keypad,column = <3>;
74 linux,code = <2>;
75 };
76
77 key_2 {
78 keypad,row = <0>;
79 keypad,column = <4>;
80 linux,code = <3>;
81 };
82
83 key_3 {
84 keypad,row = <0>;
85 keypad,column = <5>;
86 linux,code = <4>;
87 };
88 };
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index f689f49e3109..8a0060cd3982 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -21,6 +21,8 @@
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/of.h>
25#include <linux/of_gpio.h>
24#include <linux/sched.h> 26#include <linux/sched.h>
25#include <plat/keypad.h> 27#include <plat/keypad.h>
26 28
@@ -68,31 +70,26 @@ struct samsung_keypad {
68 wait_queue_head_t wait; 70 wait_queue_head_t wait;
69 bool stopped; 71 bool stopped;
70 int irq; 72 int irq;
73 enum samsung_keypad_type type;
71 unsigned int row_shift; 74 unsigned int row_shift;
72 unsigned int rows; 75 unsigned int rows;
73 unsigned int cols; 76 unsigned int cols;
74 unsigned int row_state[SAMSUNG_MAX_COLS]; 77 unsigned int row_state[SAMSUNG_MAX_COLS];
78#ifdef CONFIG_OF
79 int row_gpios[SAMSUNG_MAX_ROWS];
80 int col_gpios[SAMSUNG_MAX_COLS];
81#endif
75 unsigned short keycodes[]; 82 unsigned short keycodes[];
76}; 83};
77 84
78static int samsung_keypad_is_s5pv210(struct device *dev)
79{
80 struct platform_device *pdev = to_platform_device(dev);
81 enum samsung_keypad_type type =
82 platform_get_device_id(pdev)->driver_data;
83
84 return type == KEYPAD_TYPE_S5PV210;
85}
86
87static void samsung_keypad_scan(struct samsung_keypad *keypad, 85static void samsung_keypad_scan(struct samsung_keypad *keypad,
88 unsigned int *row_state) 86 unsigned int *row_state)
89{ 87{
90 struct device *dev = keypad->input_dev->dev.parent;
91 unsigned int col; 88 unsigned int col;
92 unsigned int val; 89 unsigned int val;
93 90
94 for (col = 0; col < keypad->cols; col++) { 91 for (col = 0; col < keypad->cols; col++) {
95 if (samsung_keypad_is_s5pv210(dev)) { 92 if (keypad->type == KEYPAD_TYPE_S5PV210) {
96 val = S5PV210_KEYIFCOLEN_MASK; 93 val = S5PV210_KEYIFCOLEN_MASK;
97 val &= ~(1 << col) << 8; 94 val &= ~(1 << col) << 8;
98 } else { 95 } else {
@@ -235,6 +232,126 @@ static void samsung_keypad_close(struct input_dev *input_dev)
235 samsung_keypad_stop(keypad); 232 samsung_keypad_stop(keypad);
236} 233}
237 234
235#ifdef CONFIG_OF
236static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
237 struct device *dev)
238{
239 struct samsung_keypad_platdata *pdata;
240 struct matrix_keymap_data *keymap_data;
241 uint32_t *keymap, num_rows = 0, num_cols = 0;
242 struct device_node *np = dev->of_node, *key_np;
243 unsigned int key_count = 0;
244
245 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
246 if (!pdata) {
247 dev_err(dev, "could not allocate memory for platform data\n");
248 return NULL;
249 }
250
251 of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows);
252 of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols);
253 if (!num_rows || !num_cols) {
254 dev_err(dev, "number of keypad rows/columns not specified\n");
255 return NULL;
256 }
257 pdata->rows = num_rows;
258 pdata->cols = num_cols;
259
260 keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
261 if (!keymap_data) {
262 dev_err(dev, "could not allocate memory for keymap data\n");
263 return NULL;
264 }
265 pdata->keymap_data = keymap_data;
266
267 for_each_child_of_node(np, key_np)
268 key_count++;
269
270 keymap_data->keymap_size = key_count;
271 keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
272 if (!keymap) {
273 dev_err(dev, "could not allocate memory for keymap\n");
274 return NULL;
275 }
276 keymap_data->keymap = keymap;
277
278 for_each_child_of_node(np, key_np) {
279 u32 row, col, key_code;
280 of_property_read_u32(key_np, "keypad,row", &row);
281 of_property_read_u32(key_np, "keypad,column", &col);
282 of_property_read_u32(key_np, "linux,code", &key_code);
283 *keymap++ = KEY(row, col, key_code);
284 }
285
286 if (of_get_property(np, "linux,input-no-autorepeat", NULL))
287 pdata->no_autorepeat = true;
288 if (of_get_property(np, "linux,input-wakeup", NULL))
289 pdata->wakeup = true;
290
291 return pdata;
292}
293
294static void samsung_keypad_parse_dt_gpio(struct device *dev,
295 struct samsung_keypad *keypad)
296{
297 struct device_node *np = dev->of_node;
298 int gpio, ret, row, col;
299
300 for (row = 0; row < keypad->rows; row++) {
301 gpio = of_get_named_gpio(np, "row-gpios", row);
302 keypad->row_gpios[row] = gpio;
303 if (!gpio_is_valid(gpio)) {
304 dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
305 row, gpio);
306 continue;
307 }
308
309 ret = gpio_request(gpio, "keypad-row");
310 if (ret)
311 dev_err(dev, "keypad row[%d] gpio request failed\n",
312 row);
313 }
314
315 for (col = 0; col < keypad->cols; col++) {
316 gpio = of_get_named_gpio(np, "col-gpios", col);
317 keypad->col_gpios[col] = gpio;
318 if (!gpio_is_valid(gpio)) {
319 dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
320 col, gpio);
321 continue;
322 }
323
324 ret = gpio_request(gpio, "keypad-col");
325 if (ret)
326 dev_err(dev, "keypad column[%d] gpio request failed\n",
327 col);
328 }
329}
330
331static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
332{
333 int cnt;
334
335 for (cnt = 0; cnt < keypad->rows; cnt++)
336 if (gpio_is_valid(keypad->row_gpios[cnt]))
337 gpio_free(keypad->row_gpios[cnt]);
338
339 for (cnt = 0; cnt < keypad->cols; cnt++)
340 if (gpio_is_valid(keypad->col_gpios[cnt]))
341 gpio_free(keypad->col_gpios[cnt]);
342}
343#else
344static
345struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
346{
347 return NULL;
348}
349
350static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
351{
352}
353#endif
354
238static int __devinit samsung_keypad_probe(struct platform_device *pdev) 355static int __devinit samsung_keypad_probe(struct platform_device *pdev)
239{ 356{
240 const struct samsung_keypad_platdata *pdata; 357 const struct samsung_keypad_platdata *pdata;
@@ -246,7 +363,10 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
246 unsigned int keymap_size; 363 unsigned int keymap_size;
247 int error; 364 int error;
248 365
249 pdata = pdev->dev.platform_data; 366 if (pdev->dev.of_node)
367 pdata = samsung_keypad_parse_dt(&pdev->dev);
368 else
369 pdata = pdev->dev.platform_data;
250 if (!pdata) { 370 if (!pdata) {
251 dev_err(&pdev->dev, "no platform data defined\n"); 371 dev_err(&pdev->dev, "no platform data defined\n");
252 return -EINVAL; 372 return -EINVAL;
@@ -303,6 +423,16 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
303 keypad->cols = pdata->cols; 423 keypad->cols = pdata->cols;
304 init_waitqueue_head(&keypad->wait); 424 init_waitqueue_head(&keypad->wait);
305 425
426 if (pdev->dev.of_node) {
427#ifdef CONFIG_OF
428 samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
429 keypad->type = of_device_is_compatible(pdev->dev.of_node,
430 "samsung,s5pv210-keypad");
431#endif
432 } else {
433 keypad->type = platform_get_device_id(pdev)->driver_data;
434 }
435
306 input_dev->name = pdev->name; 436 input_dev->name = pdev->name;
307 input_dev->id.bustype = BUS_HOST; 437 input_dev->id.bustype = BUS_HOST;
308 input_dev->dev.parent = &pdev->dev; 438 input_dev->dev.parent = &pdev->dev;
@@ -343,12 +473,19 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
343 473
344 device_init_wakeup(&pdev->dev, pdata->wakeup); 474 device_init_wakeup(&pdev->dev, pdata->wakeup);
345 platform_set_drvdata(pdev, keypad); 475 platform_set_drvdata(pdev, keypad);
476
477 if (pdev->dev.of_node) {
478 devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
479 devm_kfree(&pdev->dev, (void *)pdata->keymap_data);
480 devm_kfree(&pdev->dev, (void *)pdata);
481 }
346 return 0; 482 return 0;
347 483
348err_free_irq: 484err_free_irq:
349 free_irq(keypad->irq, keypad); 485 free_irq(keypad->irq, keypad);
350err_put_clk: 486err_put_clk:
351 clk_put(keypad->clk); 487 clk_put(keypad->clk);
488 samsung_keypad_dt_gpio_free(keypad);
352err_unmap_base: 489err_unmap_base:
353 iounmap(keypad->base); 490 iounmap(keypad->base);
354err_free_mem: 491err_free_mem:
@@ -374,6 +511,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
374 free_irq(keypad->irq, keypad); 511 free_irq(keypad->irq, keypad);
375 512
376 clk_put(keypad->clk); 513 clk_put(keypad->clk);
514 samsung_keypad_dt_gpio_free(keypad);
377 515
378 iounmap(keypad->base); 516 iounmap(keypad->base);
379 kfree(keypad); 517 kfree(keypad);
@@ -447,6 +585,17 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = {
447}; 585};
448#endif 586#endif
449 587
588#ifdef CONFIG_OF
589static const struct of_device_id samsung_keypad_dt_match[] = {
590 { .compatible = "samsung,s3c6410-keypad" },
591 { .compatible = "samsung,s5pv210-keypad" },
592 {},
593};
594MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
595#else
596#define samsung_keypad_dt_match NULL
597#endif
598
450static struct platform_device_id samsung_keypad_driver_ids[] = { 599static struct platform_device_id samsung_keypad_driver_ids[] = {
451 { 600 {
452 .name = "samsung-keypad", 601 .name = "samsung-keypad",
@@ -465,6 +614,7 @@ static struct platform_driver samsung_keypad_driver = {
465 .driver = { 614 .driver = {
466 .name = "samsung-keypad", 615 .name = "samsung-keypad",
467 .owner = THIS_MODULE, 616 .owner = THIS_MODULE,
617 .of_match_table = samsung_keypad_dt_match,
468#ifdef CONFIG_PM 618#ifdef CONFIG_PM
469 .pm = &samsung_keypad_pm_ops, 619 .pm = &samsung_keypad_pm_ops,
470#endif 620#endif