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_match); | ||
870 | |||
796 | static struct platform_driver tegra_kbc_driver = { | 871 | static struct platform_driver tegra_kbc_driver = { |
797 | .probe = tegra_kbc_probe, | 872 | .probe = tegra_kbc_probe, |
798 | .remove = __devexit_p(tegra_kbc_remove), | 873 | .remove = __devexit_p(tegra_kbc_remove), |
@@ -800,6 +875,7 @@ static struct platform_driver tegra_kbc_driver = { | |||
800 | .name = "tegra-kbc", | 875 | .name = "tegra-kbc", |
801 | .owner = THIS_MODULE, | 876 | .owner = THIS_MODULE, |
802 | .pm = &tegra_kbc_pm_ops, | 877 | .pm = &tegra_kbc_pm_ops, |
878 | .of_match_table = tegra_kbc_of_match, | ||
803 | }, | 879 | }, |
804 | }; | 880 | }; |
805 | module_platform_driver(tegra_kbc_driver); | 881 | module_platform_driver(tegra_kbc_driver); |