diff options
Diffstat (limited to 'drivers/input/touchscreen/edt-ft5x06.c')
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 145 |
1 files changed, 114 insertions, 31 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 155ab3ba84ee..9d61f1e36b33 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> | 2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> |
3 | * Lothar Waßmann <LW@KARO-electronics.de> (DT support) | ||
3 | * | 4 | * |
4 | * This software is licensed under the terms of the GNU General Public | 5 | * This software is licensed under the terms of the GNU General Public |
5 | * License version 2, as published by the Free Software Foundation, and | 6 | * License version 2, as published by the Free Software Foundation, and |
@@ -33,6 +34,7 @@ | |||
33 | #include <linux/debugfs.h> | 34 | #include <linux/debugfs.h> |
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
35 | #include <linux/gpio.h> | 36 | #include <linux/gpio.h> |
37 | #include <linux/of_gpio.h> | ||
36 | #include <linux/input/mt.h> | 38 | #include <linux/input/mt.h> |
37 | #include <linux/input/edt-ft5x06.h> | 39 | #include <linux/input/edt-ft5x06.h> |
38 | 40 | ||
@@ -65,6 +67,10 @@ struct edt_ft5x06_ts_data { | |||
65 | u16 num_x; | 67 | u16 num_x; |
66 | u16 num_y; | 68 | u16 num_y; |
67 | 69 | ||
70 | int reset_pin; | ||
71 | int irq_pin; | ||
72 | int wake_pin; | ||
73 | |||
68 | #if defined(CONFIG_DEBUG_FS) | 74 | #if defined(CONFIG_DEBUG_FS) |
69 | struct dentry *debug_dir; | 75 | struct dentry *debug_dir; |
70 | u8 *raw_buffer; | 76 | u8 *raw_buffer; |
@@ -614,24 +620,38 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) | |||
614 | #endif /* CONFIG_DEBUGFS */ | 620 | #endif /* CONFIG_DEBUGFS */ |
615 | 621 | ||
616 | static int edt_ft5x06_ts_reset(struct i2c_client *client, | 622 | static int edt_ft5x06_ts_reset(struct i2c_client *client, |
617 | int reset_pin) | 623 | struct edt_ft5x06_ts_data *tsdata) |
618 | { | 624 | { |
619 | int error; | 625 | int error; |
620 | 626 | ||
621 | if (gpio_is_valid(reset_pin)) { | 627 | if (gpio_is_valid(tsdata->wake_pin)) { |
628 | error = devm_gpio_request_one(&client->dev, | ||
629 | tsdata->wake_pin, GPIOF_OUT_INIT_LOW, | ||
630 | "edt-ft5x06 wake"); | ||
631 | if (error) { | ||
632 | dev_err(&client->dev, | ||
633 | "Failed to request GPIO %d as wake pin, error %d\n", | ||
634 | tsdata->wake_pin, error); | ||
635 | return error; | ||
636 | } | ||
637 | |||
638 | mdelay(5); | ||
639 | gpio_set_value(tsdata->wake_pin, 1); | ||
640 | } | ||
641 | if (gpio_is_valid(tsdata->reset_pin)) { | ||
622 | /* this pulls reset down, enabling the low active reset */ | 642 | /* this pulls reset down, enabling the low active reset */ |
623 | error = devm_gpio_request_one(&client->dev, reset_pin, | 643 | error = devm_gpio_request_one(&client->dev, |
624 | GPIOF_OUT_INIT_LOW, | 644 | tsdata->reset_pin, GPIOF_OUT_INIT_LOW, |
625 | "edt-ft5x06 reset"); | 645 | "edt-ft5x06 reset"); |
626 | if (error) { | 646 | if (error) { |
627 | dev_err(&client->dev, | 647 | dev_err(&client->dev, |
628 | "Failed to request GPIO %d as reset pin, error %d\n", | 648 | "Failed to request GPIO %d as reset pin, error %d\n", |
629 | reset_pin, error); | 649 | tsdata->reset_pin, error); |
630 | return error; | 650 | return error; |
631 | } | 651 | } |
632 | 652 | ||
633 | mdelay(50); | 653 | mdelay(50); |
634 | gpio_set_value(reset_pin, 1); | 654 | gpio_set_value(tsdata->reset_pin, 1); |
635 | mdelay(100); | 655 | mdelay(100); |
636 | } | 656 | } |
637 | 657 | ||
@@ -672,6 +692,20 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, | |||
672 | pdata->name <= edt_ft5x06_attr_##name.limit_high) \ | 692 | pdata->name <= edt_ft5x06_attr_##name.limit_high) \ |
673 | edt_ft5x06_register_write(tsdata, reg, pdata->name) | 693 | edt_ft5x06_register_write(tsdata, reg, pdata->name) |
674 | 694 | ||
695 | #define EDT_GET_PROP(name, reg) { \ | ||
696 | u32 val; \ | ||
697 | if (of_property_read_u32(np, #name, &val) == 0) \ | ||
698 | edt_ft5x06_register_write(tsdata, reg, val); \ | ||
699 | } | ||
700 | |||
701 | static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, | ||
702 | struct edt_ft5x06_ts_data *tsdata) | ||
703 | { | ||
704 | EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD); | ||
705 | EDT_GET_PROP(gain, WORK_REGISTER_GAIN); | ||
706 | EDT_GET_PROP(offset, WORK_REGISTER_OFFSET); | ||
707 | } | ||
708 | |||
675 | static void | 709 | static void |
676 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, | 710 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, |
677 | const struct edt_ft5x06_platform_data *pdata) | 711 | const struct edt_ft5x06_platform_data *pdata) |
@@ -699,6 +733,30 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) | |||
699 | tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); | 733 | tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); |
700 | } | 734 | } |
701 | 735 | ||
736 | #ifdef CONFIG_OF | ||
737 | static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, | ||
738 | struct edt_ft5x06_ts_data *tsdata) | ||
739 | { | ||
740 | struct device_node *np = dev->of_node; | ||
741 | |||
742 | /* | ||
743 | * irq_pin is not needed for DT setup. | ||
744 | * irq is associated via 'interrupts' property in DT | ||
745 | */ | ||
746 | tsdata->irq_pin = -EINVAL; | ||
747 | tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); | ||
748 | tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | #else | ||
753 | static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, | ||
754 | struct edt_ft5x06_ts_data *tsdata) | ||
755 | { | ||
756 | return -ENODEV; | ||
757 | } | ||
758 | #endif | ||
759 | |||
702 | static int edt_ft5x06_ts_probe(struct i2c_client *client, | 760 | static int edt_ft5x06_ts_probe(struct i2c_client *client, |
703 | const struct i2c_device_id *id) | 761 | const struct i2c_device_id *id) |
704 | { | 762 | { |
@@ -711,32 +769,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
711 | 769 | ||
712 | dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); | 770 | dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); |
713 | 771 | ||
772 | tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); | ||
773 | if (!tsdata) { | ||
774 | dev_err(&client->dev, "failed to allocate driver data.\n"); | ||
775 | return -ENOMEM; | ||
776 | } | ||
777 | |||
714 | if (!pdata) { | 778 | if (!pdata) { |
715 | dev_err(&client->dev, "no platform data?\n"); | 779 | error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); |
716 | return -EINVAL; | 780 | if (error) { |
781 | dev_err(&client->dev, | ||
782 | "DT probe failed and no platform data present\n"); | ||
783 | return error; | ||
784 | } | ||
785 | } else { | ||
786 | tsdata->reset_pin = pdata->reset_pin; | ||
787 | tsdata->irq_pin = pdata->irq_pin; | ||
788 | tsdata->wake_pin = -EINVAL; | ||
717 | } | 789 | } |
718 | 790 | ||
719 | error = edt_ft5x06_ts_reset(client, pdata->reset_pin); | 791 | error = edt_ft5x06_ts_reset(client, tsdata); |
720 | if (error) | 792 | if (error) |
721 | return error; | 793 | return error; |
722 | 794 | ||
723 | if (gpio_is_valid(pdata->irq_pin)) { | 795 | if (gpio_is_valid(tsdata->irq_pin)) { |
724 | error = devm_gpio_request_one(&client->dev, pdata->irq_pin, | 796 | error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, |
725 | GPIOF_IN, "edt-ft5x06 irq"); | 797 | GPIOF_IN, "edt-ft5x06 irq"); |
726 | if (error) { | 798 | if (error) { |
727 | dev_err(&client->dev, | 799 | dev_err(&client->dev, |
728 | "Failed to request GPIO %d, error %d\n", | 800 | "Failed to request GPIO %d, error %d\n", |
729 | pdata->irq_pin, error); | 801 | tsdata->irq_pin, error); |
730 | return error; | 802 | return error; |
731 | } | 803 | } |
732 | } | 804 | } |
733 | 805 | ||
734 | tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); | ||
735 | if (!tsdata) { | ||
736 | dev_err(&client->dev, "failed to allocate driver data.\n"); | ||
737 | return -ENOMEM; | ||
738 | } | ||
739 | |||
740 | input = devm_input_allocate_device(&client->dev); | 806 | input = devm_input_allocate_device(&client->dev); |
741 | if (!input) { | 807 | if (!input) { |
742 | dev_err(&client->dev, "failed to allocate input device.\n"); | 808 | dev_err(&client->dev, "failed to allocate input device.\n"); |
@@ -754,7 +820,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
754 | return error; | 820 | return error; |
755 | } | 821 | } |
756 | 822 | ||
757 | edt_ft5x06_ts_get_defaults(tsdata, pdata); | 823 | if (!pdata) |
824 | edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); | ||
825 | else | ||
826 | edt_ft5x06_ts_get_defaults(tsdata, pdata); | ||
827 | |||
758 | edt_ft5x06_ts_get_parameters(tsdata); | 828 | edt_ft5x06_ts_get_parameters(tsdata); |
759 | 829 | ||
760 | dev_dbg(&client->dev, | 830 | dev_dbg(&client->dev, |
@@ -784,10 +854,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
784 | input_set_drvdata(input, tsdata); | 854 | input_set_drvdata(input, tsdata); |
785 | i2c_set_clientdata(client, tsdata); | 855 | i2c_set_clientdata(client, tsdata); |
786 | 856 | ||
787 | error = devm_request_threaded_irq(&client->dev, client->irq, | 857 | error = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
788 | NULL, edt_ft5x06_ts_isr, | 858 | edt_ft5x06_ts_isr, |
789 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 859 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
790 | client->name, tsdata); | 860 | client->name, tsdata); |
791 | if (error) { | 861 | if (error) { |
792 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); | 862 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); |
793 | return error; | 863 | return error; |
@@ -798,19 +868,21 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
798 | return error; | 868 | return error; |
799 | 869 | ||
800 | error = input_register_device(input); | 870 | error = input_register_device(input); |
801 | if (error) { | 871 | if (error) |
802 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); | 872 | goto err_remove_attrs; |
803 | return error; | ||
804 | } | ||
805 | 873 | ||
806 | edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); | 874 | edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); |
807 | device_init_wakeup(&client->dev, 1); | 875 | device_init_wakeup(&client->dev, 1); |
808 | 876 | ||
809 | dev_dbg(&client->dev, | 877 | dev_dbg(&client->dev, |
810 | "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n", | 878 | "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", |
811 | pdata->irq_pin, pdata->reset_pin); | 879 | client->irq, tsdata->wake_pin, tsdata->reset_pin); |
812 | 880 | ||
813 | return 0; | 881 | return 0; |
882 | |||
883 | err_remove_attrs: | ||
884 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); | ||
885 | return error; | ||
814 | } | 886 | } |
815 | 887 | ||
816 | static int edt_ft5x06_ts_remove(struct i2c_client *client) | 888 | static int edt_ft5x06_ts_remove(struct i2c_client *client) |
@@ -854,10 +926,21 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = { | |||
854 | }; | 926 | }; |
855 | MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); | 927 | MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); |
856 | 928 | ||
929 | #ifdef CONFIG_OF | ||
930 | static const struct of_device_id edt_ft5x06_of_match[] = { | ||
931 | { .compatible = "edt,edt-ft5206", }, | ||
932 | { .compatible = "edt,edt-ft5306", }, | ||
933 | { .compatible = "edt,edt-ft5406", }, | ||
934 | { /* sentinel */ } | ||
935 | }; | ||
936 | MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); | ||
937 | #endif | ||
938 | |||
857 | static struct i2c_driver edt_ft5x06_ts_driver = { | 939 | static struct i2c_driver edt_ft5x06_ts_driver = { |
858 | .driver = { | 940 | .driver = { |
859 | .owner = THIS_MODULE, | 941 | .owner = THIS_MODULE, |
860 | .name = "edt_ft5x06", | 942 | .name = "edt_ft5x06", |
943 | .of_match_table = of_match_ptr(edt_ft5x06_of_match), | ||
861 | .pm = &edt_ft5x06_ts_pm_ops, | 944 | .pm = &edt_ft5x06_ts_pm_ops, |
862 | }, | 945 | }, |
863 | .id_table = edt_ft5x06_ts_id, | 946 | .id_table = edt_ft5x06_ts_id, |