diff options
| author | Olof Johansson <olof@lixom.net> | 2011-12-29 12:58:16 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-12-30 03:26:00 -0500 |
| commit | a445c7f0afb9114ef3de2d123f2c851787cf9d11 (patch) | |
| tree | 554783015eee8cc895ee73ca0f5137ab0984f9b3 /drivers/input | |
| parent | 5245db49d44e6033fece4d9f5946f8970c0d9ca1 (diff) | |
Input: tegra-kbc - add device tree bindings
This adds a simple device tree binding to the tegra keyboard controller.
Also, mark the default keymap as __devinitdata since it is not referenced
after boot.
Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 92 |
1 files changed, 84 insertions, 8 deletions
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 08d02f2c6a88..b77725db4bea 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
| 27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
| 28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
| 29 | #include <linux/of.h> | ||
| 29 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
| 30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 31 | #include <mach/clk.h> | 32 | #include <mach/clk.h> |
| @@ -82,7 +83,7 @@ struct tegra_kbc { | |||
| 82 | struct clk *clk; | 83 | struct clk *clk; |
| 83 | }; | 84 | }; |
| 84 | 85 | ||
| 85 | static const u32 tegra_kbc_default_keymap[] = { | 86 | static const u32 tegra_kbc_default_keymap[] __devinitdata = { |
| 86 | KEY(0, 2, KEY_W), | 87 | KEY(0, 2, KEY_W), |
| 87 | KEY(0, 3, KEY_S), | 88 | KEY(0, 3, KEY_S), |
| 88 | KEY(0, 4, KEY_A), | 89 | KEY(0, 4, KEY_A), |
| @@ -217,7 +218,8 @@ static const u32 tegra_kbc_default_keymap[] = { | |||
| 217 | KEY(31, 4, KEY_HELP), | 218 | KEY(31, 4, KEY_HELP), |
| 218 | }; | 219 | }; |
| 219 | 220 | ||
| 220 | static const struct matrix_keymap_data tegra_kbc_default_keymap_data = { | 221 | static const |
| 222 | struct matrix_keymap_data tegra_kbc_default_keymap_data __devinitdata = { | ||
| 221 | .keymap = tegra_kbc_default_keymap, | 223 | .keymap = tegra_kbc_default_keymap, |
| 222 | .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), | 224 | .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), |
| 223 | }; | 225 | }; |
| @@ -576,6 +578,56 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, | |||
| 576 | return true; | 578 | return true; |
| 577 | } | 579 | } |
| 578 | 580 | ||
| 581 | #ifdef CONFIG_OF | ||
| 582 | static struct tegra_kbc_platform_data * __devinit | ||
| 583 | tegra_kbc_dt_parse_pdata(struct platform_device *pdev) | ||
| 584 | { | ||
| 585 | struct tegra_kbc_platform_data *pdata; | ||
| 586 | struct device_node *np = pdev->dev.of_node; | ||
| 587 | |||
| 588 | if (!np) | ||
| 589 | return NULL; | ||
| 590 | |||
| 591 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 592 | if (!pdata) | ||
| 593 | return NULL; | ||
| 594 | |||
| 595 | if (!of_property_read_u32(np, "debounce-delay", &prop)) | ||
| 596 | pdata->debounce_cnt = prop; | ||
| 597 | |||
| 598 | if (!of_property_read_u32(np, "repeat-delay", &prop)) | ||
| 599 | pdata->repeat_cnt = prop; | ||
| 600 | |||
| 601 | if (of_find_property(np, "needs-ghost-filter", NULL)) | ||
| 602 | pdata->use_ghost_filter = true; | ||
| 603 | |||
| 604 | if (of_find_property(np, "wakeup-source", NULL)) | ||
| 605 | pdata->wakeup = true; | ||
| 606 | |||
| 607 | /* | ||
| 608 | * All currently known keymaps with device tree support use the same | ||
| 609 | * pin_cfg, so set it up here. | ||
| 610 | */ | ||
| 611 | for (i = 0; i < KBC_MAX_ROW; i++) { | ||
| 612 | pdata->pin_cfg[i].num = i; | ||
| 613 | pdata->pin_cfg[i].is_row = true; | ||
| 614 | } | ||
| 615 | |||
| 616 | for (i = 0; i < KBC_MAX_COL; i++) { | ||
| 617 | pdata->pin_cfg[KBC_MAX_ROW + i].num = i; | ||
| 618 | pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false; | ||
| 619 | } | ||
| 620 | |||
| 621 | return pdata; | ||
| 622 | } | ||
| 623 | #else | ||
| 624 | static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( | ||
| 625 | struct platform_device *pdev) | ||
| 626 | { | ||
| 627 | return NULL; | ||
| 628 | } | ||
| 629 | #endif | ||
| 630 | |||
| 579 | static int __devinit tegra_kbc_probe(struct platform_device *pdev) | 631 | static int __devinit tegra_kbc_probe(struct platform_device *pdev) |
| 580 | { | 632 | { |
| 581 | const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; | 633 | const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; |
| @@ -590,21 +642,28 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) | |||
| 590 | unsigned int scan_time_rows; | 642 | unsigned int scan_time_rows; |
| 591 | 643 | ||
| 592 | if (!pdata) | 644 | if (!pdata) |
| 593 | return -EINVAL; | 645 | pdata = tegra_kbc_dt_parse_pdata(pdev); |
| 594 | 646 | ||
| 595 | if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) | 647 | if (!pdata) |
| 596 | return -EINVAL; | 648 | return -EINVAL; |
| 597 | 649 | ||
| 650 | if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) { | ||
| 651 | err = -EINVAL; | ||
| 652 | goto err_free_pdata; | ||
| 653 | } | ||
| 654 | |||
| 598 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 655 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 599 | if (!res) { | 656 | if (!res) { |
| 600 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | 657 | dev_err(&pdev->dev, "failed to get I/O memory\n"); |
| 601 | return -ENXIO; | 658 | err = -ENXIO; |
| 659 | goto err_free_pdata; | ||
| 602 | } | 660 | } |
| 603 | 661 | ||
| 604 | irq = platform_get_irq(pdev, 0); | 662 | irq = platform_get_irq(pdev, 0); |
| 605 | if (irq < 0) { | 663 | if (irq < 0) { |
| 606 | dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); | 664 | dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); |
| 607 | return -ENXIO; | 665 | err = -ENXIO; |
| 666 | goto err_free_pdata; | ||
| 608 | } | 667 | } |
| 609 | 668 | ||
| 610 | kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); | 669 | kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); |
| @@ -706,6 +765,9 @@ err_free_mem_region: | |||
| 706 | err_free_mem: | 765 | err_free_mem: |
| 707 | input_free_device(input_dev); | 766 | input_free_device(input_dev); |
| 708 | kfree(kbc); | 767 | kfree(kbc); |
| 768 | err_free_pdata: | ||
| 769 | if (!pdev->dev.platform_data) | ||
| 770 | kfree(pdata); | ||
| 709 | 771 | ||
| 710 | return err; | 772 | return err; |
| 711 | } | 773 | } |
| @@ -715,6 +777,8 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev) | |||
| 715 | struct tegra_kbc *kbc = platform_get_drvdata(pdev); | 777 | struct tegra_kbc *kbc = platform_get_drvdata(pdev); |
| 716 | struct resource *res; | 778 | struct resource *res; |
| 717 | 779 | ||
| 780 | platform_set_drvdata(pdev, NULL); | ||
| 781 | |||
| 718 | free_irq(kbc->irq, pdev); | 782 | free_irq(kbc->irq, pdev); |
| 719 | clk_put(kbc->clk); | 783 | clk_put(kbc->clk); |
| 720 | 784 | ||
| @@ -723,9 +787,14 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev) | |||
| 723 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 787 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 724 | release_mem_region(res->start, resource_size(res)); | 788 | release_mem_region(res->start, resource_size(res)); |
| 725 | 789 | ||
| 726 | kfree(kbc); | 790 | /* |
| 791 | * If we do not have platform data attached to the device we | ||
| 792 | * allocated it ourselves and thus need to free it. | ||
| 793 | */ | ||
| 794 | if (!pdev->dev.platform_data) | ||
| 795 | kfree(kbc->pdata); | ||
| 727 | 796 | ||
| 728 | platform_set_drvdata(pdev, NULL); | 797 | kfree(kbc); |
| 729 | 798 | ||
| 730 | return 0; | 799 | return 0; |
| 731 | } | 800 | } |
| @@ -793,6 +862,12 @@ static int tegra_kbc_resume(struct device *dev) | |||
| 793 | 862 | ||
| 794 | static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); | 863 | static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); |
| 795 | 864 | ||
| 865 | static const struct of_device_id tegra_kbc_of_match[] = { | ||
| 866 | { .compatible = "nvidia,tegra20-kbc", }, | ||
| 867 | { }, | ||
| 868 | }; | ||
| 869 | MODULE_DEVICE_TABLE(of, tegra_kbc_of | ||
