diff options
author | Dudley Du <dudley.dulixin@gmail.com> | 2014-11-09 15:36:34 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-11-10 01:59:48 -0500 |
commit | b1cfa7b4388285c0f0b486f152ab0cb18612c779 (patch) | |
tree | 6ad423475d8f90c72633865e21957017398ea895 | |
parent | bd447b61c49fc26f0299587db3e6d66da49dc529 (diff) |
Input: cyapa - switch to using managed resources
Use of managed resources simplifies error handling and device removal code.
Signed-off-by: Dudley Du <dudl@cypress.com>
[Dmitry: added open/close methods so cyapa_remove is no longer needed.]
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/mouse/cyapa.c | 184 |
1 files changed, 105 insertions, 79 deletions
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 1d978c7289b4..c84a9ebeb2ff 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c | |||
@@ -577,10 +577,13 @@ static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode) | |||
577 | power = ret & ~PWR_MODE_MASK; | 577 | power = ret & ~PWR_MODE_MASK; |
578 | power |= power_mode & PWR_MODE_MASK; | 578 | power |= power_mode & PWR_MODE_MASK; |
579 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); | 579 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); |
580 | if (ret < 0) | 580 | if (ret < 0) { |
581 | dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", | 581 | dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", |
582 | power_mode, ret); | 582 | power_mode, ret); |
583 | return ret; | 583 | return ret; |
584 | } | ||
585 | |||
586 | return 0; | ||
584 | } | 587 | } |
585 | 588 | ||
586 | static int cyapa_get_query_data(struct cyapa *cyapa) | 589 | static int cyapa_get_query_data(struct cyapa *cyapa) |
@@ -753,16 +756,40 @@ static u8 cyapa_check_adapter_functionality(struct i2c_client *client) | |||
753 | return ret; | 756 | return ret; |
754 | } | 757 | } |
755 | 758 | ||
759 | static int cyapa_open(struct input_dev *input) | ||
760 | { | ||
761 | struct cyapa *cyapa = input_get_drvdata(input); | ||
762 | struct i2c_client *client = cyapa->client; | ||
763 | int error; | ||
764 | |||
765 | error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | ||
766 | if (error) { | ||
767 | dev_err(&client->dev, "set active power failed: %d\n", error); | ||
768 | return error; | ||
769 | } | ||
770 | |||
771 | enable_irq(client->irq); | ||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static void cyapa_close(struct input_dev *input) | ||
776 | { | ||
777 | struct cyapa *cyapa = input_get_drvdata(input); | ||
778 | |||
779 | disable_irq(cyapa->client->irq); | ||
780 | cyapa_set_power_mode(cyapa, PWR_MODE_OFF); | ||
781 | } | ||
782 | |||
756 | static int cyapa_create_input_dev(struct cyapa *cyapa) | 783 | static int cyapa_create_input_dev(struct cyapa *cyapa) |
757 | { | 784 | { |
758 | struct device *dev = &cyapa->client->dev; | 785 | struct device *dev = &cyapa->client->dev; |
759 | int ret; | ||
760 | struct input_dev *input; | 786 | struct input_dev *input; |
787 | int error; | ||
761 | 788 | ||
762 | if (!cyapa->physical_size_x || !cyapa->physical_size_y) | 789 | if (!cyapa->physical_size_x || !cyapa->physical_size_y) |
763 | return -EINVAL; | 790 | return -EINVAL; |
764 | 791 | ||
765 | input = cyapa->input = input_allocate_device(); | 792 | input = devm_input_allocate_device(dev); |
766 | if (!input) { | 793 | if (!input) { |
767 | dev_err(dev, "allocate memory for input device failed\n"); | 794 | dev_err(dev, "allocate memory for input device failed\n"); |
768 | return -ENOMEM; | 795 | return -ENOMEM; |
@@ -775,6 +802,9 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) | |||
775 | input->id.product = 0; /* means any product in eventcomm. */ | 802 | input->id.product = 0; /* means any product in eventcomm. */ |
776 | input->dev.parent = &cyapa->client->dev; | 803 | input->dev.parent = &cyapa->client->dev; |
777 | 804 | ||
805 | input->open = cyapa_open; | ||
806 | input->close = cyapa_close; | ||
807 | |||
778 | input_set_drvdata(input, cyapa); | 808 | input_set_drvdata(input, cyapa); |
779 | 809 | ||
780 | __set_bit(EV_ABS, input->evbit); | 810 | __set_bit(EV_ABS, input->evbit); |
@@ -802,34 +832,24 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) | |||
802 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | 832 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
803 | 833 | ||
804 | /* handle pointer emulation and unused slots in core */ | 834 | /* handle pointer emulation and unused slots in core */ |
805 | ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, | 835 | error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, |
806 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); | 836 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); |
807 | if (ret) { | 837 | if (error) { |
808 | dev_err(dev, "allocate memory for MT slots failed, %d\n", ret); | 838 | dev_err(dev, "failed to initialize MT slots: %d\n", error); |
809 | goto err_free_device; | 839 | return error; |
810 | } | 840 | } |
811 | 841 | ||
812 | /* Register the device in input subsystem */ | 842 | cyapa->input = input; |
813 | ret = input_register_device(input); | ||
814 | if (ret) { | ||
815 | dev_err(dev, "input device register failed, %d\n", ret); | ||
816 | goto err_free_device; | ||
817 | } | ||
818 | return 0; | 843 | return 0; |
819 | |||
820 | err_free_device: | ||
821 | input_free_device(input); | ||
822 | cyapa->input = NULL; | ||
823 | return ret; | ||
824 | } | 844 | } |
825 | 845 | ||
826 | static int cyapa_probe(struct i2c_client *client, | 846 | static int cyapa_probe(struct i2c_client *client, |
827 | const struct i2c_device_id *dev_id) | 847 | const struct i2c_device_id *dev_id) |
828 | { | 848 | { |
829 | int ret; | ||
830 | u8 adapter_func; | ||
831 | struct cyapa *cyapa; | ||
832 | struct device *dev = &client->dev; | 849 | struct device *dev = &client->dev; |
850 | struct cyapa *cyapa; | ||
851 | u8 adapter_func; | ||
852 | int error; | ||
833 | 853 | ||
834 | adapter_func = cyapa_check_adapter_functionality(client); | 854 | adapter_func = cyapa_check_adapter_functionality(client); |
835 | if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) { | 855 | if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) { |
@@ -837,11 +857,9 @@ static int cyapa_probe(struct i2c_client *client, | |||
837 | return -EIO; | 857 | return -EIO; |
838 | } | 858 | } |
839 | 859 | ||
840 | cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL); | 860 | cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL); |
841 | if (!cyapa) { | 861 | if (!cyapa) |
842 | dev_err(dev, "allocate memory for cyapa failed\n"); | ||
843 | return -ENOMEM; | 862 | return -ENOMEM; |
844 | } | ||
845 | 863 | ||
846 | cyapa->gen = CYAPA_GEN3; | 864 | cyapa->gen = CYAPA_GEN3; |
847 | cyapa->client = client; | 865 | cyapa->client = client; |
@@ -852,66 +870,61 @@ static int cyapa_probe(struct i2c_client *client, | |||
852 | /* i2c isn't supported, use smbus */ | 870 | /* i2c isn't supported, use smbus */ |
853 | if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) | 871 | if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) |
854 | cyapa->smbus = true; | 872 | cyapa->smbus = true; |
873 | |||
855 | cyapa->state = CYAPA_STATE_NO_DEVICE; | 874 | cyapa->state = CYAPA_STATE_NO_DEVICE; |
856 | ret = cyapa_check_is_operational(cyapa); | ||
857 | if (ret) { | ||
858 | dev_err(dev, "device not operational, %d\n", ret); | ||
859 | goto err_mem_free; | ||
860 | } | ||
861 | 875 | ||
862 | ret = cyapa_create_input_dev(cyapa); | 876 | error = cyapa_check_is_operational(cyapa); |
863 | if (ret) { | 877 | if (error) { |
864 | dev_err(dev, "create input_dev instance failed, %d\n", ret); | 878 | dev_err(dev, "device not operational, %d\n", error); |
865 | goto err_mem_free; | 879 | return error; |
866 | } | 880 | } |
867 | 881 | ||
868 | ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | 882 | /* Power down the device until we need it */ |
869 | if (ret) { | 883 | error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF); |
870 | dev_err(dev, "set active power failed, %d\n", ret); | 884 | if (error) { |
871 | goto err_unregister_device; | 885 | dev_err(dev, "failed to quiesce the device: %d\n", error); |
886 | return error; | ||
872 | } | 887 | } |
873 | 888 | ||
874 | cyapa->irq = client->irq; | 889 | error = cyapa_create_input_dev(cyapa); |
875 | ret = request_threaded_irq(cyapa->irq, | 890 | if (error) |
876 | NULL, | 891 | return error; |
877 | cyapa_irq, | 892 | |
878 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 893 | error = devm_request_threaded_irq(dev, client->irq, |
879 | "cyapa", | 894 | NULL, cyapa_irq, |
880 | cyapa); | 895 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
881 | if (ret) { | 896 | "cyapa", cyapa); |
882 | dev_err(dev, "IRQ request failed: %d\n, ", ret); | 897 | if (error) { |
883 | goto err_unregister_device; | 898 | dev_err(dev, "IRQ request failed: %d\n, ", error); |
899 | return error; | ||
884 | } | 900 | } |
885 | 901 | ||
886 | return 0; | 902 | /* Disable IRQ until the device is opened */ |
887 | 903 | disable_irq(client->irq); | |
888 | err_unregister_device: | ||
889 | input_unregister_device(cyapa->input); | ||
890 | err_mem_free: | ||
891 | kfree(cyapa); | ||
892 | 904 | ||
893 | return ret; | 905 | /* Register the device in input subsystem */ |
894 | } | 906 | error = input_register_device(cyapa->input); |
895 | 907 | if (error) { | |
896 | static int cyapa_remove(struct i2c_client *client) | 908 | dev_err(dev, "failed to register input device: %d\n", error); |
897 | { | 909 | return error; |
898 | struct cyapa *cyapa = i2c_get_clientdata(client); | 910 | } |
899 | |||
900 | free_irq(cyapa->irq, cyapa); | ||
901 | input_unregister_device(cyapa->input); | ||
902 | cyapa_set_power_mode(cyapa, PWR_MODE_OFF); | ||
903 | kfree(cyapa); | ||
904 | 911 | ||
905 | return 0; | 912 | return 0; |
906 | } | 913 | } |
907 | 914 | ||
908 | static int __maybe_unused cyapa_suspend(struct device *dev) | 915 | static int __maybe_unused cyapa_suspend(struct device *dev) |
909 | { | 916 | { |
910 | int ret; | 917 | struct i2c_client *client = to_i2c_client(dev); |
918 | struct cyapa *cyapa = i2c_get_clientdata(client); | ||
919 | struct input_dev *input = cyapa->input; | ||
911 | u8 power_mode; | 920 | u8 power_mode; |
912 | struct cyapa *cyapa = dev_get_drvdata(dev); | 921 | int error; |
922 | |||
923 | error = mutex_lock_interruptible(&input->mutex); | ||
924 | if (error) | ||
925 | return error; | ||
913 | 926 | ||
914 | disable_irq(cyapa->irq); | 927 | disable_irq(client->irq); |
915 | 928 | ||
916 | /* | 929 | /* |
917 | * Set trackpad device to idle mode if wakeup is allowed, | 930 | * Set trackpad device to idle mode if wakeup is allowed, |
@@ -919,28 +932,42 @@ static int __maybe_unused cyapa_suspend(struct device *dev) | |||
919 | */ | 932 | */ |
920 | power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE | 933 | power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE |
921 | : PWR_MODE_OFF; | 934 | : PWR_MODE_OFF; |
922 | ret = cyapa_set_power_mode(cyapa, power_mode); | 935 | error = cyapa_set_power_mode(cyapa, power_mode); |
923 | if (ret < 0) | 936 | if (error) |
924 | dev_err(dev, "set power mode failed, %d\n", ret); | 937 | dev_err(dev, "resume: set power mode to %d failed: %d\n", |
938 | power_mode, error); | ||
925 | 939 | ||
926 | if (device_may_wakeup(dev)) | 940 | if (device_may_wakeup(dev)) |
927 | cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0); | 941 | cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0); |
942 | |||
943 | mutex_unlock(&input->mutex); | ||
944 | |||
928 | return 0; | 945 | return 0; |
929 | } | 946 | } |
930 | 947 | ||
931 | static int __maybe_unused cyapa_resume(struct device *dev) | 948 | static int __maybe_unused cyapa_resume(struct device *dev) |
932 | { | 949 | { |
933 | int ret; | 950 | struct i2c_client *client = to_i2c_client(dev); |
934 | struct cyapa *cyapa = dev_get_drvdata(dev); | 951 | struct cyapa *cyapa = i2c_get_clientdata(client); |
952 | struct input_dev *input = cyapa->input; | ||
953 | u8 power_mode; | ||
954 | int error; | ||
955 | |||
956 | mutex_lock(&input->mutex); | ||
935 | 957 | ||
936 | if (device_may_wakeup(dev) && cyapa->irq_wake) | 958 | if (device_may_wakeup(dev) && cyapa->irq_wake) |
937 | disable_irq_wake(cyapa->irq); | 959 | disable_irq_wake(cyapa->irq); |
938 | 960 | ||
939 | ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | 961 | power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF; |
940 | if (ret) | 962 | error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); |
941 | dev_warn(dev, "resume active power failed, %d\n", ret); | 963 | if (error) |
964 | dev_warn(dev, "resume: set power mode to %d failed: %d\n", | ||
965 | power_mode, error); | ||
942 | 966 | ||
943 | enable_irq(cyapa->irq); | 967 | enable_irq(cyapa->irq); |
968 | |||
969 | mutex_unlock(&input->mutex); | ||
970 | |||
944 | return 0; | 971 | return 0; |
945 | } | 972 | } |
946 | 973 | ||
@@ -960,7 +987,6 @@ static struct i2c_driver cyapa_driver = { | |||
960 | }, | 987 | }, |
961 | 988 | ||
962 | .probe = cyapa_probe, | 989 | .probe = cyapa_probe, |
963 | .remove = cyapa_remove, | ||
964 | .id_table = cyapa_id_table, | 990 | .id_table = cyapa_id_table, |
965 | }; | 991 | }; |
966 | 992 | ||