diff options
| author | AnilKumar Ch <anilkumar@ti.com> | 2012-11-21 01:49:31 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-11-21 01:55:10 -0500 |
| commit | 4a83eecff65bd327bf5cb3b400b96fa975c73308 (patch) | |
| tree | 78e4fabcc1cc60875a6a557a215bc93c110e4536 /drivers/input | |
| parent | 5383116b86d8e877684770d05acd1dda62be102d (diff) | |
Input: matrix-keypad - add device tree support
Also the driver was modifued to take advantage of recent improvements in
matrix_keypad_build_keymap() implementation, which automatically allocates
memory for keymap.
The driver was tested on AM335x EVM.
Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 119 |
1 files changed, 97 insertions, 22 deletions
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 18b72372028a..05d3a969ff4e 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c | |||
| @@ -23,6 +23,9 @@ | |||
| 23 | #include <linux/gpio.h> | 23 | #include <linux/gpio.h> |
| 24 | #include <linux/input/matrix_keypad.h> | 24 | #include <linux/input/matrix_keypad.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/of.h> | ||
| 27 | #include <linux/of_gpio.h> | ||
| 28 | #include <linux/of_platform.h> | ||
| 26 | 29 | ||
| 27 | struct matrix_keypad { | 30 | struct matrix_keypad { |
| 28 | const struct matrix_keypad_platform_data *pdata; | 31 | const struct matrix_keypad_platform_data *pdata; |
| @@ -37,8 +40,6 @@ struct matrix_keypad { | |||
| 37 | bool scan_pending; | 40 | bool scan_pending; |
| 38 | bool stopped; | 41 | bool stopped; |
| 39 | bool gpio_all_disabled; | 42 | bool gpio_all_disabled; |
| 40 | |||
| 41 | unsigned short keycodes[]; | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | /* | 45 | /* |
| @@ -118,6 +119,7 @@ static void matrix_keypad_scan(struct work_struct *work) | |||
| 118 | struct matrix_keypad *keypad = | 119 | struct matrix_keypad *keypad = |
| 119 | container_of(work, struct matrix_keypad, work.work); | 120 | container_of(work, struct matrix_keypad, work.work); |
| 120 | struct input_dev *input_dev = keypad->input_dev; | 121 | struct input_dev *input_dev = keypad->input_dev; |
| 122 | const unsigned short *keycodes = input_dev->keycode; | ||
| 121 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | 123 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; |
| 122 | uint32_t new_state[MATRIX_MAX_COLS]; | 124 | uint32_t new_state[MATRIX_MAX_COLS]; |
| 123 | int row, col, code; | 125 | int row, col, code; |
| @@ -153,7 +155,7 @@ static void matrix_keypad_scan(struct work_struct *work) | |||
| 153 | code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); | 155 | code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); |
| 154 | input_event(input_dev, EV_MSC, MSC_SCAN, code); | 156 | input_event(input_dev, EV_MSC, MSC_SCAN, code); |
| 155 | input_report_key(input_dev, | 157 | input_report_key(input_dev, |
| 156 | keypad->keycodes[code], | 158 | keycodes[code], |
| 157 | new_state[col] & (1 << row)); | 159 | new_state[col] & (1 << row)); |
| 158 | } | 160 | } |
| 159 | } | 161 | } |
| @@ -394,33 +396,95 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) | |||
| 394 | gpio_free(pdata->col_gpios[i]); | 396 | gpio_free(pdata->col_gpios[i]); |
| 395 | } | 397 | } |
| 396 | 398 | ||
| 399 | #ifdef CONFIG_OF | ||
| 400 | static struct matrix_keypad_platform_data * __devinit | ||
| 401 | matrix_keypad_parse_dt(struct device *dev) | ||
| 402 | { | ||
| 403 | struct matrix_keypad_platform_data *pdata; | ||
| 404 | struct device_node *np = dev->of_node; | ||
| 405 | unsigned int *gpios; | ||
| 406 | int i; | ||
| 407 | |||
| 408 | if (!np) { | ||
| 409 | dev_err(dev, "device lacks DT data\n"); | ||
| 410 | return ERR_PTR(-ENODEV); | ||
| 411 | } | ||
| 412 | |||
| 413 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
| 414 | if (!pdata) { | ||
| 415 | dev_err(dev, "could not allocate memory for platform data\n"); | ||
| 416 | return ERR_PTR(-ENOMEM); | ||
| 417 | } | ||
| 418 | |||
| 419 | pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios"); | ||
| 420 | pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios"); | ||
| 421 | if (!pdata->num_row_gpios || !pdata->num_col_gpios) { | ||
| 422 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
| 423 | return ERR_PTR(-EINVAL); | ||
| 424 | } | ||
| 425 | |||
| 426 | if (of_get_property(np, "linux,no-autorepeat", NULL)) | ||
| 427 | pdata->no_autorepeat = true; | ||
| 428 | if (of_get_property(np, "linux,wakeup", NULL)) | ||
| 429 | pdata->wakeup = true; | ||
| 430 | if (of_get_property(np, "gpio-activelow", NULL)) | ||
| 431 | pdata->active_low = true; | ||
| 432 | |||
| 433 | of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms); | ||
| 434 | of_property_read_u32(np, "col-scan-delay-us", | ||
| 435 | &pdata->col_scan_delay_us); | ||
| 436 | |||
| 437 | gpios = devm_kzalloc(dev, | ||
| 438 | sizeof(unsigned int) * | ||
| 439 | (pdata->num_row_gpios + pdata->num_col_gpios), | ||
| 440 | GFP_KERNEL); | ||
| 441 | if (!gpios) { | ||
| 442 | dev_err(dev, "could not allocate memory for gpios\n"); | ||
| 443 | return ERR_PTR(-ENOMEM); | ||
| 444 | } | ||
| 445 | |||
| 446 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
| 447 | gpios[i] = of_get_named_gpio(np, "row-gpios", i); | ||
| 448 | |||
| 449 | for (i = 0; i < pdata->num_col_gpios; i++) | ||
| 450 | gpios[pdata->num_row_gpios + i] = | ||
| 451 | of_get_named_gpio(np, "col-gpios", i); | ||
| 452 | |||
| 453 | pdata->row_gpios = gpios; | ||
| 454 | pdata->col_gpios = &gpios[pdata->num_row_gpios]; | ||
| 455 | |||
| 456 | return pdata; | ||
| 457 | } | ||
| 458 | #else | ||
| 459 | static inline struct matrix_keypad_platform_data * | ||
| 460 | matrix_keypad_parse_dt(struct device *dev) | ||
| 461 | { | ||
| 462 | dev_err(dev, "no platform data defined\n"); | ||
| 463 | |||
| 464 | return ERR_PTR(-EINVAL); | ||
| 465 | } | ||
| 466 | #endif | ||
| 467 | |||
| 397 | static int __devinit matrix_keypad_probe(struct platform_device *pdev) | 468 | static int __devinit matrix_keypad_probe(struct platform_device *pdev) |
| 398 | { | 469 | { |
| 399 | const struct matrix_keypad_platform_data *pdata; | 470 | const struct matrix_keypad_platform_data *pdata; |
| 400 | const struct matrix_keymap_data *keymap_data; | ||
| 401 | struct matrix_keypad *keypad; | 471 | struct matrix_keypad *keypad; |
| 402 | struct input_dev *input_dev; | 472 | struct input_dev *input_dev; |
| 403 | unsigned int row_shift; | ||
| 404 | size_t keymap_size; | ||
| 405 | int err; | 473 | int err; |
| 406 | 474 | ||
| 407 | pdata = pdev->dev.platform_data; | 475 | pdata = dev_get_platdata(&pdev->dev); |
| 408 | if (!pdata) { | 476 | if (!pdata) { |
| 409 | dev_err(&pdev->dev, "no platform data defined\n"); | 477 | pdata = matrix_keypad_parse_dt(&pdev->dev); |
| 410 | return -EINVAL; | 478 | if (IS_ERR(pdata)) { |
| 411 | } | 479 | dev_err(&pdev->dev, "no platform data defined\n"); |
| 412 | 480 | return PTR_ERR(pdata); | |
| 413 | keymap_data = pdata->keymap_data; | 481 | } |
| 414 | if (!keymap_data) { | 482 | } else if (!pdata->keymap_data) { |
| 415 | dev_err(&pdev->dev, "no keymap data defined\n"); | 483 | dev_err(&pdev->dev, "no keymap data defined\n"); |
| 416 | return -EINVAL; | 484 | return -EINVAL; |
| 417 | } | 485 | } |
| 418 | 486 | ||
| 419 | row_shift = get_count_order(pdata->num_col_gpios); | 487 | keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); |
| 420 | keymap_size = (pdata->num_row_gpios << row_shift) * | ||
| 421 | sizeof(keypad->keycodes[0]); | ||
| 422 | keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size, | ||
| 423 | GFP_KERNEL); | ||
| 424 | input_dev = input_allocate_device(); | 488 | input_dev = input_allocate_device(); |
| 425 | if (!keypad || !input_dev) { | 489 | if (!keypad || !input_dev) { |
| 426 | err = -ENOMEM; | 490 | err = -ENOMEM; |
| @@ -429,7 +493,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) | |||
| 429 | 493 | ||
| 430 | keypad->input_dev = input_dev; | 494 | keypad->input_dev = input_dev; |
| 431 | keypad->pdata = pdata; | 495 | keypad->pdata = pdata; |
| 432 | keypad->row_shift = row_shift; | 496 | keypad->row_shift = get_count_order(pdata->num_col_gpios); |
| 433 | keypad->stopped = true; | 497 | keypad->stopped = true; |
| 434 | INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); | 498 | INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); |
| 435 | spin_lock_init(&keypad->lock); | 499 | spin_lock_init(&keypad->lock); |
| @@ -440,12 +504,14 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) | |||
| 440 | input_dev->open = matrix_keypad_start; | 504 | input_dev->open = matrix_keypad_start; |
| 441 | input_dev->close = matrix_keypad_stop; | 505 | input_dev->close = matrix_keypad_stop; |
| 442 | 506 | ||
| 443 | err = matrix_keypad_build_keymap(keymap_data, NULL, | 507 | err = matrix_keypad_build_keymap(pdata->keymap_data, NULL, |
| 444 | pdata->num_row_gpios, | 508 | pdata->num_row_gpios, |
| 445 | pdata->num_col_gpios, | 509 | pdata->num_col_gpios, |
| 446 | keypad->keycodes, input_dev); | 510 | NULL, input_dev); |
| 447 | if (err) | 511 | if (err) { |
| 512 | dev_err(&pdev->dev, "failed to build keymap\n"); | ||
| 448 | goto err_free_mem; | 513 | goto err_free_mem; |
| 514 | } | ||
| 449 | 515 | ||
| 450 | if (!pdata->no_autorepeat) | 516 | if (!pdata->no_autorepeat) |
| 451 | __set_bit(EV_REP, input_dev->evbit); | 517 | __set_bit(EV_REP, input_dev->evbit); |
| @@ -488,6 +554,14 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev) | |||
| 488 | return 0; | 554 | return 0; |
| 489 | } | 555 | } |
| 490 | 556 | ||
| 557 | #ifdef CONFIG_OF | ||
| 558 | static const struct of_device_id matrix_keypad_dt_match[] = { | ||
| 559 | { .compatible = "gpio-matrix-keypad" }, | ||
| 560 | { } | ||
| 561 | }; | ||
| 562 | MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); | ||
| 563 | #endif | ||
| 564 | |||
| 491 | static struct platform_driver matrix_keypad_driver = { | 565 | static struct platform_driver matrix_keypad_driver = { |
| 492 | .probe = matrix_keypad_probe, | 566 | .probe = matrix_keypad_probe, |
| 493 | .remove = __devexit_p(matrix_keypad_remove), | 567 | .remove = __devexit_p(matrix_keypad_remove), |
| @@ -495,6 +569,7 @@ static struct platform_driver matrix_keypad_driver = { | |||
| 495 | .name = "matrix-keypad", | 569 | .name = "matrix-keypad", |
| 496 | .owner = THIS_MODULE, | 570 | .owner = THIS_MODULE, |
| 497 | .pm = &matrix_keypad_pm_ops, | 571 | .pm = &matrix_keypad_pm_ops, |
| 572 | .of_match_table = of_match_ptr(matrix_keypad_dt_match), | ||
| 498 | }, | 573 | }, |
| 499 | }; | 574 | }; |
| 500 | module_platform_driver(matrix_keypad_driver); | 575 | module_platform_driver(matrix_keypad_driver); |
